Add files

This commit is contained in:
Mario Hüttel 2023-08-10 23:00:40 +02:00
commit 9f6219a2cf
35 changed files with 73071 additions and 0 deletions

41
firmware/.gitignore vendored Normal file
View File

@ -0,0 +1,41 @@
# Created by https://www.toptal.com/developers/gitignore/api/c++
# Edit at https://www.toptal.com/developers/gitignore?templates=c++
### C++ ###
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# End of https://www.toptal.com/developers/gitignore/api/c++
*.jdebug
obj/*

116
firmware/LICENSE Normal file
View File

@ -0,0 +1,116 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author
This program 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 2 of the License, or (at your option) any later version.
This program 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice

102
firmware/Makefile Normal file
View File

@ -0,0 +1,102 @@
################################Shimatta Makefile####################################
#CPU: STM32L052
#Compiler: arm-none-eabi
#####################################################################################
ifneq ($(VERBOSE),true)
QUIET=@
else
QUIET=
endif
#Add Files and Folders below#########################################################
CFILES = main.c syscalls/syscalls.c setup/system_init.c startup/startup_stm32l052x8xx.c usb.c unique-id.c eeprom.c
ASFILES =
INCLUDEPATH = -Iinclude -Iinclude/cmsis
OBJDIR=obj
target = project
LIBRARYPATH = -Lstartup
LIBRARIES =
DEFINES = -DSTM32L052xx -DSTM32L0
mapfile = memmap
##Custom Files###
#TODO
###################################################################################
CC=arm-none-eabi-gcc
OBJCOPY=arm-none-eabi-objcopy
OBJDUMP=arm-none-eabi-objdump
SIZE=arm-none-eabi-size
LFLAGS = -mlittle-endian -mthumb -mcpu=cortex-m0plus -mthumb-interwork
LFLAGS += -mfloat-abi=soft --disable-newlib-supplied-syscalls -nostartfiles
LFLAGS += -Tstartup/stm32l052x8xx.ld -Wl,-Map=$(mapfile).map -Wl,--gc-sections -g -Wl,--print-memory-usage
CFLAGS = -c -fmessage-length=0 -mlittle-endian -mthumb -mcpu=cortex-m0plus -mthumb-interwork
CFLAGS += -mfloat-abi=soft -nostartfiles -Wall -g -O0
####################################################################################
OBJ = $(CFILES:%.c=$(OBJDIR)/%.c.o)
ASOBJ = $(ASFILES:%.S=$(OBJDIR)/%.S.o)
default: $(target).elf
binary: $(target).bin $(target).hex
%.bin: %.elf
$(OBJCOPY) -O binary $^ $@
%.hex: %.elf
$(OBJCOPY) -O ihex $^ $@
#Linking
$(target).elf: $(OBJ) $(ASOBJ)
@echo Linking $@
$(QUIET)$(CC) $(LFLAGS) $(LIBRARYPATH) -o $@ $^ $(LIBRARIES)
$(QUIET)$(SIZE) $@
#Compiling
$(OBJ):
@echo Compiling $@
$(eval OUTPATH=$(dir $@))
@mkdir -p $(OUTPATH)
$(QUIET)$(CC) $(CFLAGS) -MMD -MT $@ $(INCLUDEPATH) $(DEFINES) -o $@ $(@:$(OBJDIR)/%.c.o=%.c)
$(ASOBJ):
@echo Compiling $@
$(eval OUTPATH=$(dir $@))
@mkdir -p $(OUTPATH)
$(QUIET)$(CC) $(CFLAGS) -MMD -MT $@ $(INCLUDEPATH) $(DEFINES) -o $@ $(@:$(OBJDIR)/%.S.o=%.S)
.PHONY: qtproject clean mrproper objcopy disassemble
disassemble: $(target).elf
$(OBJDUMP) -D -s $< > $(target).lss
objcopy: $(target).bin $(target).hex
mrproper:
rm -f $(target).pro
clean:
rm -f $(target).elf $(target).bin $(target).hex $(OBJ) $(ASOBJ) $(mapfile).map $(target).lss
rm -rfv $(OBJDIR)
qtproject:
echo -e "TEMPLATE = app\nCONFIG -= console app_bundle qt" > $(target).pro
echo -e "SOURCES += $(CFILES) $(ASFILES)" >> $(target).pro
echo -ne "INCLUDEPATH += " >> $(target).pro
echo "$(INCLUDEPATH)" | sed "s!-I!./!g" >> $(target).pro
echo -ne "HEADERS += " >> $(target).pro
find -name "*.h" | tr "\\n" " " >> $(target).pro
echo -ne "\nDEFINES += " >> $(target).pro
echo "$(DEFINES)" | sed "s/-D//g" >> $(target).pro
-include $(CFILES:%.c=$(OBJDIR)/%.c.d) $(ASFILES:%.S=$(OBJDIR)/%.S.d)

2
firmware/README.md Normal file
View File

@ -0,0 +1,2 @@
# stm32l052x8xx-template

86
firmware/eeprom.c Normal file
View File

@ -0,0 +1,86 @@
#include "eeprom.h"
#include <stm32l0xx.h>
/**
* @brief Defined in Linkerscript as the start of the EEPROM
*/
extern uint32_t __ld_seeprom;
int data_eeprom_write_word(uint32_t word_addr_offset, uint32_t word)
{
uint32_t *eeprom_base_addr = &__ld_seeprom;
/* Unlock the NVM interface */
FLASH->PEKEYR = 0x89ABCDEFUL;
FLASH->PEKEYR = 0x02030405UL;
__DSB();
/* Check if we are unlocked */
if (FLASH->PECR & FLASH_PECR_PELOCK)
return -1;
FLASH->PECR &= ~(FLASH_PECR_PELOCK | FLASH_PECR_ERASE);
eeprom_base_addr += word_addr_offset;
*eeprom_base_addr = word;
/* Lock the flash interface again */
FLASH->PECR |= FLASH_PECR_PELOCK;
return 0;
}
int data_eeprom_write(uint32_t byte_offset, const uint8_t *data, uint32_t len)
{
char *eeprom_base_addr = (char *)&__ld_seeprom;
char *dest_ptr;
uint32_t *word_dest_ptr;
uint32_t full_words;
uint32_t remain_bytes;
/* Unlock the NVM interface */
FLASH->PEKEYR = 0x89ABCDEFUL;
FLASH->PEKEYR = 0x02030405UL;
__DSB();
/* Check if we are unlocked */
if (FLASH->PECR & FLASH_PECR_PELOCK)
return -1;
FLASH->PECR &= ~(FLASH_PECR_PELOCK | FLASH_PECR_ERASE);
dest_ptr = eeprom_base_addr + byte_offset;
/* Do the first bytes */
while ((uint32_t)dest_ptr & 0x3) {
*(dest_ptr++) = *(data++);
len -= 1;
}
/* Do the remianing words */
full_words = len / 4;
remain_bytes = len % 4;
while (full_words) {
word_dest_ptr = (uint32_t *)dest_ptr;
*word_dest_ptr = (((uint32_t)data[3]) << 24) | (((uint32_t)data[2]) << 16) | (((uint32_t)data[1]) << 8) |
(((uint32_t)data[0]) << 0);
dest_ptr += 4;
data += 4;
full_words--;
}
while (remain_bytes) {
*dest_ptr = *data;
dest_ptr++;
data++;
remain_bytes--;
}
/* Lock the flash interface again */
FLASH->PECR |= FLASH_PECR_PELOCK;
return 0;
}

10
firmware/eeprom.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _EEPROM_H_
#define _EEPROM_H_
#include <stdint.h>
int data_eeprom_write_word(uint32_t word_addr_offset, uint32_t word);
int data_eeprom_write(uint32_t byte_offset, const uint8_t *data, uint32_t len);
#endif /* _EEPROM_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,914 @@
/**************************************************************************//**
* @file core_cm0plus.h
* @brief CMSIS Cortex-M0+ Core Peripheral Access Layer Header File
* @version V4.30
* @date 20. October 2015
******************************************************************************/
/* Copyright (c) 2009 - 2015 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CORE_CM0PLUS_H_GENERIC
#define __CORE_CM0PLUS_H_GENERIC
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
\page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions
CMSIS violates the following MISRA-C:2004 rules:
\li Required Rule 8.5, object/function definition in header file.<br>
Function definitions in header files are used to allow 'inlining'.
\li Required Rule 18.4, declaration of union type or object of union type: '{...}'.<br>
Unions are used for effective representation of core registers.
\li Advisory Rule 19.7, Function-like macro defined.<br>
Function-like macros are used to allow more efficient code.
*/
/*******************************************************************************
* CMSIS definitions
******************************************************************************/
/**
\ingroup Cortex-M0+
@{
*/
/* CMSIS CM0+ definitions */
#define __CM0PLUS_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */
#define __CM0PLUS_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */
#define __CM0PLUS_CMSIS_VERSION ((__CM0PLUS_CMSIS_VERSION_MAIN << 16U) | \
__CM0PLUS_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */
#define __CORTEX_M (0x00U) /*!< Cortex-M Core */
#if defined ( __CC_ARM )
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#define __STATIC_INLINE static __inline
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#define __ASM __asm /*!< asm keyword for ARM Compiler */
#define __INLINE __inline /*!< inline keyword for ARM Compiler */
#define __STATIC_INLINE static __inline
#elif defined ( __GNUC__ )
#define __ASM __asm /*!< asm keyword for GNU Compiler */
#define __INLINE inline /*!< inline keyword for GNU Compiler */
#define __STATIC_INLINE static inline
#elif defined ( __ICCARM__ )
#define __ASM __asm /*!< asm keyword for IAR Compiler */
#define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */
#define __STATIC_INLINE static inline
#elif defined ( __TMS470__ )
#define __ASM __asm /*!< asm keyword for TI CCS Compiler */
#define __STATIC_INLINE static inline
#elif defined ( __TASKING__ )
#define __ASM __asm /*!< asm keyword for TASKING Compiler */
#define __INLINE inline /*!< inline keyword for TASKING Compiler */
#define __STATIC_INLINE static inline
#elif defined ( __CSMC__ )
#define __packed
#define __ASM _asm /*!< asm keyword for COSMIC Compiler */
#define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */
#define __STATIC_INLINE static inline
#else
#error Unknown compiler
#endif
/** __FPU_USED indicates whether an FPU is used or not.
This core does not support an FPU at all
*/
#define __FPU_USED 0U
#if defined ( __CC_ARM )
#if defined __TARGET_FPU_VFP
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#if defined __ARM_PCS_VFP
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __GNUC__ )
#if defined (__VFP_FP__) && !defined(__SOFTFP__)
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __ICCARM__ )
#if defined __ARMVFP__
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __TMS470__ )
#if defined __TI_VFP_SUPPORT__
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __TASKING__ )
#if defined __FPU_VFP__
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#elif defined ( __CSMC__ )
#if ( __CSMC__ & 0x400U)
#error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
#endif
#endif
#include "core_cmInstr.h" /* Core Instruction Access */
#include "core_cmFunc.h" /* Core Function Access */
#ifdef __cplusplus
}
#endif
#endif /* __CORE_CM0PLUS_H_GENERIC */
#ifndef __CMSIS_GENERIC
#ifndef __CORE_CM0PLUS_H_DEPENDANT
#define __CORE_CM0PLUS_H_DEPENDANT
#ifdef __cplusplus
extern "C" {
#endif
/* check device defines and use defaults */
#if defined __CHECK_DEVICE_DEFINES
#ifndef __CM0PLUS_REV
#define __CM0PLUS_REV 0x0000U
#warning "__CM0PLUS_REV not defined in device header file; using default!"
#endif
#ifndef __MPU_PRESENT
#define __MPU_PRESENT 0U
#warning "__MPU_PRESENT not defined in device header file; using default!"
#endif
#ifndef __VTOR_PRESENT
#define __VTOR_PRESENT 0U
#warning "__VTOR_PRESENT not defined in device header file; using default!"
#endif
#ifndef __NVIC_PRIO_BITS
#define __NVIC_PRIO_BITS 2U
#warning "__NVIC_PRIO_BITS not defined in device header file; using default!"
#endif
#ifndef __Vendor_SysTickConfig
#define __Vendor_SysTickConfig 0U
#warning "__Vendor_SysTickConfig not defined in device header file; using default!"
#endif
#endif
/* IO definitions (access restrictions to peripheral registers) */
/**
\defgroup CMSIS_glob_defs CMSIS Global Defines
<strong>IO Type Qualifiers</strong> are used
\li to specify the access to peripheral variables.
\li for automatic generation of peripheral register debug information.
*/
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/* following defines should be used for structure members */
#define __IM volatile const /*! Defines 'read only' structure member permissions */
#define __OM volatile /*! Defines 'write only' structure member permissions */
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
/*@} end of group Cortex-M0+ */
/*******************************************************************************
* Register Abstraction
Core Register contain:
- Core Register
- Core NVIC Register
- Core SCB Register
- Core SysTick Register
- Core MPU Register
******************************************************************************/
/**
\defgroup CMSIS_core_register Defines and Type Definitions
\brief Type definitions and defines for Cortex-M processor based devices.
*/
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_CORE Status and Control Registers
\brief Core Register type definitions.
@{
*/
/**
\brief Union type to access the Application Program Status Register (APSR).
*/
typedef union
{
struct
{
uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */
uint32_t V:1; /*!< bit: 28 Overflow condition code flag */
uint32_t C:1; /*!< bit: 29 Carry condition code flag */
uint32_t Z:1; /*!< bit: 30 Zero condition code flag */
uint32_t N:1; /*!< bit: 31 Negative condition code flag */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} APSR_Type;
/* APSR Register Definitions */
#define APSR_N_Pos 31U /*!< APSR: N Position */
#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */
#define APSR_Z_Pos 30U /*!< APSR: Z Position */
#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */
#define APSR_C_Pos 29U /*!< APSR: C Position */
#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */
#define APSR_V_Pos 28U /*!< APSR: V Position */
#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */
/**
\brief Union type to access the Interrupt Program Status Register (IPSR).
*/
typedef union
{
struct
{
uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */
uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} IPSR_Type;
/* IPSR Register Definitions */
#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */
#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */
/**
\brief Union type to access the Special-Purpose Program Status Registers (xPSR).
*/
typedef union
{
struct
{
uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */
uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */
uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */
uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */
uint32_t V:1; /*!< bit: 28 Overflow condition code flag */
uint32_t C:1; /*!< bit: 29 Carry condition code flag */
uint32_t Z:1; /*!< bit: 30 Zero condition code flag */
uint32_t N:1; /*!< bit: 31 Negative condition code flag */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} xPSR_Type;
/* xPSR Register Definitions */
#define xPSR_N_Pos 31U /*!< xPSR: N Position */
#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */
#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */
#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */
#define xPSR_C_Pos 29U /*!< xPSR: C Position */
#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */
#define xPSR_V_Pos 28U /*!< xPSR: V Position */
#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */
#define xPSR_T_Pos 24U /*!< xPSR: T Position */
#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */
#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */
#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */
/**
\brief Union type to access the Control Registers (CONTROL).
*/
typedef union
{
struct
{
uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */
uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */
uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} CONTROL_Type;
/* CONTROL Register Definitions */
#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */
#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */
#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */
#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */
/*@} end of group CMSIS_CORE */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC)
\brief Type definitions for the NVIC Registers
@{
*/
/**
\brief Structure type to access the Nested Vectored Interrupt Controller (NVIC).
*/
typedef struct
{
__IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
uint32_t RESERVED0[31U];
__IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
uint32_t RSERVED1[31U];
__IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
uint32_t RESERVED2[31U];
__IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
uint32_t RESERVED3[31U];
uint32_t RESERVED4[64U];
__IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */
} NVIC_Type;
/*@} end of group CMSIS_NVIC */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_SCB System Control Block (SCB)
\brief Type definitions for the System Control Block Registers
@{
*/
/**
\brief Structure type to access the System Control Block (SCB).
*/
typedef struct
{
__IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
__IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
#if (__VTOR_PRESENT == 1U)
__IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */
#else
uint32_t RESERVED0;
#endif
__IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
__IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
__IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
uint32_t RESERVED1;
__IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */
__IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
} SCB_Type;
/* SCB CPUID Register Definitions */
#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */
#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */
#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */
#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */
#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */
#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */
#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */
#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */
#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */
#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */
/* SCB Interrupt Control State Register Definitions */
#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */
#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */
#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */
#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */
#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */
#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */
#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */
#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */
#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */
#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */
#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */
#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */
#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */
#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */
#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */
#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */
#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */
#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */
#if (__VTOR_PRESENT == 1U)
/* SCB Interrupt Control State Register Definitions */
#define SCB_VTOR_TBLOFF_Pos 8U /*!< SCB VTOR: TBLOFF Position */
#define SCB_VTOR_TBLOFF_Msk (0xFFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */
#endif
/* SCB Application Interrupt and Reset Control Register Definitions */
#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */
#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */
#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */
#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */
#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */
#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */
#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */
#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */
#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */
#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */
/* SCB System Control Register Definitions */
#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */
#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */
#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */
#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */
#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */
#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */
/* SCB Configuration Control Register Definitions */
#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */
#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */
#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */
#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */
/* SCB System Handler Control and State Register Definitions */
#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */
#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */
/*@} end of group CMSIS_SCB */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_SysTick System Tick Timer (SysTick)
\brief Type definitions for the System Timer Registers.
@{
*/
/**
\brief Structure type to access the System Timer (SysTick).
*/
typedef struct
{
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
__IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
__IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;
/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */
/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */
/* SysTick Current Register Definitions */
#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */
/* SysTick Calibration Register Definitions */
#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */
#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */
#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */
/*@} end of group CMSIS_SysTick */
#if (__MPU_PRESENT == 1U)
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_MPU Memory Protection Unit (MPU)
\brief Type definitions for the Memory Protection Unit (MPU)
@{
*/
/**
\brief Structure type to access the Memory Protection Unit (MPU).
*/
typedef struct
{
__IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */
__IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */
__IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */
__IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */
__IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */
} MPU_Type;
/* MPU Type Register Definitions */
#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */
#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */
#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */
#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */
#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */
#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */
/* MPU Control Register Definitions */
#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */
#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */
#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */
#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */
#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */
#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */
/* MPU Region Number Register Definitions */
#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */
#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */
/* MPU Region Base Address Register Definitions */
#define MPU_RBAR_ADDR_Pos 8U /*!< MPU RBAR: ADDR Position */
#define MPU_RBAR_ADDR_Msk (0xFFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */
#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */
#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */
#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */
#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */
/* MPU Region Attribute and Size Register Definitions */
#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */
#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */
#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */
#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */
#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */
#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */
#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */
#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */
#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */
#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */
#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */
#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */
#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */
#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */
#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */
#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */
#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */
#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */
#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */
#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */
/*@} end of group CMSIS_MPU */
#endif
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug)
\brief Cortex-M0+ Core Debug Registers (DCB registers, SHCSR, and DFSR) are only accessible over DAP and not via processor.
Therefore they are not covered by the Cortex-M0+ header file.
@{
*/
/*@} end of group CMSIS_CoreDebug */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_core_bitfield Core register bit field macros
\brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk).
@{
*/
/**
\brief Mask and shift a bit field value for use in a register bit range.
\param[in] field Name of the register bit field.
\param[in] value Value of the bit field.
\return Masked and shifted value.
*/
#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk)
/**
\brief Mask and shift a register value to extract a bit filed value.
\param[in] field Name of the register bit field.
\param[in] value Value of register.
\return Masked and shifted bit field value.
*/
#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos)
/*@} end of group CMSIS_core_bitfield */
/**
\ingroup CMSIS_core_register
\defgroup CMSIS_core_base Core Definitions
\brief Definitions for base addresses, unions, and structures.
@{
*/
/* Memory mapping of Cortex-M0+ Hardware */
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */
#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */
#if (__MPU_PRESENT == 1U)
#define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */
#define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */
#endif
/*@} */
/*******************************************************************************
* Hardware Abstraction Layer
Core Function Interface contains:
- Core NVIC Functions
- Core SysTick Functions
- Core Register Access Functions
******************************************************************************/
/**
\defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference
*/
/* ########################## NVIC functions #################################### */
/**
\ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_NVICFunctions NVIC Functions
\brief Functions that manage interrupts and exceptions via the NVIC.
@{
*/
/* Interrupt Priorities are WORD accessible only under ARMv6M */
/* The following MACROS handle generation of the register offset and byte masks */
#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL)
#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) )
#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) )
/**
\brief Enable External Interrupt
\details Enables a device-specific interrupt in the NVIC interrupt controller.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
/**
\brief Disable External Interrupt
\details Disables a device-specific interrupt in the NVIC interrupt controller.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
{
NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
/**
\brief Get Pending Interrupt
\details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt.
\param [in] IRQn Interrupt number.
\return 0 Interrupt status is not pending.
\return 1 Interrupt status is pending.
*/
__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL));
}
/**
\brief Set Pending Interrupt
\details Sets the pending bit of an external interrupt.
\param [in] IRQn Interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
/**
\brief Clear Pending Interrupt
\details Clears the pending bit of an external interrupt.
\param [in] IRQn External interrupt number. Value cannot be negative.
*/
__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}
/**
\brief Set Interrupt Priority
\details Sets the priority of an interrupt.
\note The priority cannot be set for every core interrupt.
\param [in] IRQn Interrupt number.
\param [in] priority Priority to set.
*/
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if ((int32_t)(IRQn) < 0)
{
SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
(((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
}
else
{
NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) |
(((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn)));
}
}
/**
\brief Get Interrupt Priority
\details Reads the priority of an interrupt.
The interrupt number can be positive to specify an external (device specific) interrupt,
or negative to specify an internal (core) interrupt.
\param [in] IRQn Interrupt number.
\return Interrupt Priority.
Value is aligned automatically to the implemented priority bits of the microcontroller.
*/
__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn)
{
if ((int32_t)(IRQn) < 0)
{
return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS)));
}
else
{
return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS)));
}
}
/**
\brief System Reset
\details Initiates a system reset request to reset the MCU.
*/
__STATIC_INLINE void NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included
buffered write are completed before reset */
SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
SCB_AIRCR_SYSRESETREQ_Msk);
__DSB(); /* Ensure completion of memory access */
for(;;) /* wait until reset */
{
__NOP();
}
}
/*@} end of CMSIS_Core_NVICFunctions */
/* ################################## SysTick function ############################################ */
/**
\ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_SysTickFunctions SysTick Functions
\brief Functions that configure the System.
@{
*/
#if (__Vendor_SysTickConfig == 0U)
/**
\brief System Tick Configuration
\details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
Counter is in free running mode to generate periodic interrupts.
\param [in] ticks Number of ticks between two interrupts.
\return 0 Function succeeded.
\return 1 Function failed.
\note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
must contain a vendor-specific implementation of this function.
*/
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}
#endif
/*@} end of CMSIS_Core_SysTickFunctions */
#ifdef __cplusplus
}
#endif
#endif /* __CORE_CM0PLUS_H_DEPENDANT */
#endif /* __CMSIS_GENERIC */

View File

@ -0,0 +1,87 @@
/**************************************************************************//**
* @file core_cmFunc.h
* @brief CMSIS Cortex-M Core Function Access Header File
* @version V4.30
* @date 20. October 2015
******************************************************************************/
/* Copyright (c) 2009 - 2015 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CORE_CMFUNC_H
#define __CORE_CMFUNC_H
/* ########################### Core Function Access ########################### */
/** \ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
@{
*/
/*------------------ RealView Compiler -----------------*/
#if defined ( __CC_ARM )
#include "cmsis_armcc.h"
/*------------------ ARM Compiler V6 -------------------*/
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#include "cmsis_armcc_V6.h"
/*------------------ GNU Compiler ----------------------*/
#elif defined ( __GNUC__ )
#include "cmsis_gcc.h"
/*------------------ ICC Compiler ----------------------*/
#elif defined ( __ICCARM__ )
#include <cmsis_iar.h>
/*------------------ TI CCS Compiler -------------------*/
#elif defined ( __TMS470__ )
#include <cmsis_ccs.h>
/*------------------ TASKING Compiler ------------------*/
#elif defined ( __TASKING__ )
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all intrinsics,
* Including the CMSIS ones.
*/
/*------------------ COSMIC Compiler -------------------*/
#elif defined ( __CSMC__ )
#include <cmsis_csm.h>
#endif
/*@} end of CMSIS_Core_RegAccFunctions */
#endif /* __CORE_CMFUNC_H */

View File

@ -0,0 +1,87 @@
/**************************************************************************//**
* @file core_cmInstr.h
* @brief CMSIS Cortex-M Core Instruction Access Header File
* @version V4.30
* @date 20. October 2015
******************************************************************************/
/* Copyright (c) 2009 - 2015 ARM LIMITED
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of ARM nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
*
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef __CORE_CMINSTR_H
#define __CORE_CMINSTR_H
/* ########################## Core Instruction Access ######################### */
/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface
Access to dedicated instructions
@{
*/
/*------------------ RealView Compiler -----------------*/
#if defined ( __CC_ARM )
#include "cmsis_armcc.h"
/*------------------ ARM Compiler V6 -------------------*/
#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#include "cmsis_armcc_V6.h"
/*------------------ GNU Compiler ----------------------*/
#elif defined ( __GNUC__ )
#include "cmsis_gcc.h"
/*------------------ ICC Compiler ----------------------*/
#elif defined ( __ICCARM__ )
#include <cmsis_iar.h>
/*------------------ TI CCS Compiler -------------------*/
#elif defined ( __TMS470__ )
#include <cmsis_ccs.h>
/*------------------ TASKING Compiler ------------------*/
#elif defined ( __TASKING__ )
/*
* The CMSIS functions have been implemented as intrinsics in the compiler.
* Please use "carm -?i" to get an up to date list of all intrinsics,
* Including the CMSIS ones.
*/
/*------------------ COSMIC Compiler -------------------*/
#elif defined ( __CSMC__ )
#include <cmsis_csm.h>
#endif
/*@}*/ /* end of group CMSIS_Core_InstructionInterface */
#endif /* __CORE_CMINSTR_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,235 @@
/**
******************************************************************************
* @file stm32l0xx.h
* @author MCD Application Team
* @brief CMSIS Cortex-M0+ Device Peripheral Access Layer Header File.
* This file contains all the peripheral register's definitions, bits
* definitions and memory mapping for STM32L0xx devices.
*
* The file is the unique include file that the application programmer
* is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select:
* - The device used in the target application
* - To use or not the peripheral's drivers in application code(i.e.
* code will be based on direct access to peripheral's registers
* rather than drivers API), this option is controlled by
* "#define USE_HAL_DRIVER"
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright(c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32l0xx
* @{
*/
#ifndef __STM32L0xx_H
#define __STM32L0xx_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Library_configuration_section
* @{
*/
/**
* @brief STM32 Family
*/
#if !defined (STM32L0)
#define STM32L0
#endif /* STM32L0 */
/* Uncomment the line below according to the target STM32 device used in your
application
*/
#if !defined (STM32L010x4) && !defined (STM32L010x6) && !defined (STM32L010x8) && !defined (STM32L010xB) && \
!defined (STM32L011xx) && !defined (STM32L021xx) && \
!defined (STM32L031xx) && !defined (STM32L041xx) && \
!defined (STM32L051xx) && !defined (STM32L052xx) && !defined (STM32L053xx) && \
!defined (STM32L062xx) && !defined (STM32L063xx) && \
!defined (STM32L071xx) && !defined (STM32L072xx) && !defined (STM32L073xx) && \
!defined (STM32L081xx) && !defined (STM32L082xx) && !defined (STM32L083xx)
/* #define STM32L010x4 */ /*!< STM32L010K4, STM32L010F4 Devices */
/* #define STM32L010x6 */ /*!< STM32L010C6 Devices */
/* #define STM32L010x8 */ /*!< STM32L010K8, STM32L010R8 Devices */
/* #define STM32L010xB */ /*!< STM32L010RB Devices */
/* #define STM32L011xx */ /*!< STM32L031C6, STM32L031E6, STM32L031F6, STM32L031G6, STM32L031K6 Devices */
/* #define STM32L021xx */ /*!< STM32L021D4, STM32L021F4, STM32L021G4, STM32L021K4 Devices */
/* #define STM32L031xx */ /*!< STM32L031C6, STM32L031E6, STM32L031F6, STM32L031G6, STM32L031K6 Devices */
/* #define STM32L041xx */ /*!< STM32L041C6, STM32L041K6, STM32L041G6, STM32L041F6, STM32L041E6 Devices */
/* #define STM32L051xx */ /*!< STM32L051K8, STM32L051C6, STM32L051C8, STM32L051R6, STM32L051R8, STM32L051K6, STM32L051T6, STM32L051T8 Devices */
/* #define STM32L052xx */ /*!< STM32L052K6, STM32L052K8, STM32L052C6, STM32L052C8, STM32L052R6, STM32L052R8, STM32L052T6, STM32L052T8 Devices */
/* #define STM32L053xx */ /*!< STM32L053C6, STM32L053C8, STM32L053R6, STM32L053R8 Devices */
/* #define STM32L062xx */ /*!< STM32L062K8 Devices */
/* #define STM32L063xx */ /*!< STM32L063C8, STM32L063R8 Devices */
/* #define STM32L071xx */ /*!< STM32L071V8, STM32L071K8, STM32L071VB, STM32L071RB, STM32L071CB, STM32L071KB, STM32L071VZ, STM32L071RZ, STM32L071CZ, STM32L071KZ, STM32L071C8 Devices */
/* #define STM32L072xx */ /*!< STM32L072V8, STM32L072VB, STM32L072RB, STM32L072CB, STM32L072VZ, STM32L072RZ, STM32L072CZ, STM32L072KB, STM32L072KZ Devices */
/* #define STM32L073xx */ /*!< STM32L073V8, STM32L073VB, STM32L073RB, STM32L073VZ, STM32L073RZ, STM32L073CB, STM32L073CZ Devices */
/* #define STM32L081xx */ /*!< STM32L081CB, STM32L081CZ, STM32L081KZ Devices */
/* #define STM32L082xx */ /*!< STM32L082KB, STM32L082KZ, STM32L082CZ Devices */
/* #define STM32L083xx */ /*!< STM32L083V8, STM32L083VB, STM32L083RB, STM32L083VZ, STM32L083RZ, STM32L083CB, STM32L083CZ Devices */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor.
*/
#if !defined (USE_HAL_DRIVER)
/**
* @brief Comment the line below if you will not use the peripherals drivers.
In this case, these drivers will not be included and the application code will
be based on direct access to peripherals registers
*/
/*#define USE_HAL_DRIVER */
#endif /* USE_HAL_DRIVER */
/**
* @brief CMSIS Device version number
*/
#define __STM32L0xx_CMSIS_VERSION_MAIN (0x01) /*!< [31:24] main version */
#define __STM32L0xx_CMSIS_VERSION_SUB1 (0x09) /*!< [23:16] sub1 version */
#define __STM32L0xx_CMSIS_VERSION_SUB2 (0x01) /*!< [15:8] sub2 version */
#define __STM32L0xx_CMSIS_VERSION_RC (0x00) /*!< [7:0] release candidate */
#define __STM32L0xx_CMSIS_VERSION ((__STM32L0xx_CMSIS_VERSION_MAIN << 24)\
|(__STM32L0xx_CMSIS_VERSION_SUB1 << 16)\
|(__STM32L0xx_CMSIS_VERSION_SUB2 << 8 )\
|(__STM32L0xx_CMSIS_VERSION_RC))
/**
* @}
*/
/** @addtogroup Device_Included
* @{
*/
#if defined(STM32L010xB)
#include "stm32l010xb.h"
#elif defined(STM32L010x8)
#include "stm32l010x8.h"
#elif defined(STM32L010x6)
#include "stm32l010x6.h"
#elif defined(STM32L010x4)
#include "stm32l010x4.h"
#elif defined(STM32L011xx)
#include "stm32l011xx.h"
#elif defined(STM32L021xx)
#include "stm32l021xx.h"
#elif defined(STM32L031xx)
#include "stm32l031xx.h"
#elif defined(STM32L041xx)
#include "stm32l041xx.h"
#elif defined(STM32L051xx)
#include "stm32l051xx.h"
#elif defined(STM32L052xx)
#include "stm32l052xx.h"
#elif defined(STM32L053xx)
#include "stm32l053xx.h"
#elif defined(STM32L062xx)
#include "stm32l062xx.h"
#elif defined(STM32L063xx)
#include "stm32l063xx.h"
#elif defined(STM32L071xx)
#include "stm32l071xx.h"
#elif defined(STM32L072xx)
#include "stm32l072xx.h"
#elif defined(STM32L073xx)
#include "stm32l073xx.h"
#elif defined(STM32L082xx)
#include "stm32l082xx.h"
#elif defined(STM32L083xx)
#include "stm32l083xx.h"
#elif defined(STM32L081xx)
#include "stm32l081xx.h"
#else
#error "Please select first the target STM32L0xx device used in your application (in stm32l0xx.h file)"
#endif
/**
* @}
*/
/** @addtogroup Exported_types
* @{
*/
typedef enum
{
RESET = 0,
SET = !RESET
} FlagStatus, ITStatus;
typedef enum
{
DISABLE = 0,
ENABLE = !DISABLE
} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
typedef enum
{
SUCCESS = 0,
ERROR = !SUCCESS
} ErrorStatus;
/**
* @}
*/
/** @addtogroup Exported_macro
* @{
*/
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
/**
* @}
*/
#if defined (USE_HAL_DRIVER)
#include "stm32l0xx_hal.h"
#endif /* USE_HAL_DRIVER */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __STM32L0xx_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

13
firmware/macro_helpers.h Normal file
View File

@ -0,0 +1,13 @@
/**
* General Macro Helpers
*
* Kevin Cuzner
*/
#ifndef _MACRO_HELPERS_H_
#define _MACRO_HELPERS_H_
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#endif //_MACRO_HELPERS_H_

506
firmware/main.c Normal file
View File

@ -0,0 +1,506 @@
#include <stm32l0xx.h>
#include <stdint.h>
#include <stddef.h>
#include "usb.h"
#include "unique-id.h"
#include "eeprom.h"
#include <string.h>
volatile unsigned int i = 0x12345678;
unsigned char c = 2;
unsigned int my_static_var;
volatile uint32_t tick = 0;
uint8_t ep0_buff[64];
uint8_t dev_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x00, 0x02, // bcdUSB
0x00, // bDeviceClass = Use info in interface descriptor
0x00, // bDeviceSubClass = Use info in interface
0x00, // bDeviceProtocol = Use info in interface
64, // bMaxPacketSize0
0xAD, 0xDE, // idVendor
0xEF, 0xBE, // idProduct
0x00, 0x01, // bcdDevice
1, // iManufacturer
2, // iProduct
3, // iSerialNumber
1 // bNumConfigurations
};
/* See: https://github.com/anszom/avr-vusb-keyboard/blob/master/sw/hid_descriptor.h */
const uint8_t hid_report_descriptor[] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs) //1 byte
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs) //1 byte
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs) //6 bytes
0xc0 // END_COLLECTION
};
struct hid_report {
uint8_t modifier;
uint8_t reserved;
uint8_t keycodes[6];
};
const uint8_t config_desc[34] = {
9, /* bLenght */
2, /* bDescriptorType */
34, 0, /* wTotalLength */
1, /* bNumInterfaces */
1, /* bConfigurationValue */
0, /* iConfiguration */
0x80, /* bmAttributes */
50, /* bMaxPower */
/* Interface Descriptor */
0x09, /* Length = 9 */
0x04, /* Type = Interface Descriptor */
0x00, /* Interface Number */
0x00, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x03, /* bInterfaceClass (3 = HID) */
0x00, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
0x00, /* iInterface */
/* Endpoint Descriptor: EP1 Interrupt IN */
0x07, /* bLength */
0x05, /* bDescriptorType (5 = endpoint) */
0x81, /* bEndpointAddress */
0x03, /* bmAttributes (3 = Interrupt transfer */
64, 0x00, /* MaxPacketSize */
10, /* bInterval */
/* HID Descriptor */
9, /* bLength */
0x21, /* Descriptor Type: 0x21 = HID */
0x11, 0x01, /* BCD HID */
0x00, /* bCountryCode */
1, /* bNumDescriptors */
0x22, /* bDescriptorType 0x22=report */
sizeof(hid_report_descriptor), 0x00
};
const uint8_t lang_zero_desc[4] = {
4, /* bLength */
3, /* Descriptor Type = string */
0x09, 0x04 /* Language ID = English (US) */
};
const uint8_t manufacturer_string_desc[] =
{
2 + 8 * 2, /* Length */
3, /* Type = String descriptor */
'S', 0x00,
'h', 0x00,
'i', 0x00,
'm', 0x00,
'a', 0x00,
't', 0x00,
't', 0x00,
'a', 0x00,
};
const uint8_t product_string_desc[] =
{
2 + 22 * 2, /* Length */
3, /* Type = String descriptor */
'S', 0x00,
'u', 0x00,
's', 0x00,
't', 0x00,
'a', 0x00,
'i', 0x00,
'n', 0x00,
' ', 0x00,
'P', 0x00,
'e', 0x00,
'd', 0x00,
'a', 0x00,
'l', 0x00,
' ', 0x00,
'K', 0x00,
'e', 0x00,
'y', 0x00,
'b', 0x00,
'o', 0x00,
'a', 0x00,
'r', 0x00,
'd', 0x00,
};
uint8_t serial_string_desc[25 * 2 + 10];
struct usb_descriptor_entry desc_table[] = {
{0x0000, 0x0100, dev_descriptor, sizeof(dev_descriptor)},
{0x0000, 0x0200, config_desc, sizeof(config_desc)},
{0x0000, 0x0300, lang_zero_desc, sizeof(lang_zero_desc)},
{0x0409, 0x0301, manufacturer_string_desc, sizeof(manufacturer_string_desc)},
{0x0409, 0x0302, product_string_desc, sizeof(product_string_desc)},
{0x0409, 0x0303, serial_string_desc, sizeof(serial_string_desc)},
{0x0000, 0x2200, hid_report_descriptor, sizeof(hid_report_descriptor)},
{0x0001, 0x2200, hid_report_descriptor, sizeof(hid_report_descriptor)},
/* sentinel */
{0x00, 0x0, NULL, 0},
};
static void wait_for_ticks(uint32_t ticks)
{
tick = 0;
while (tick < ticks);
}
static void uint_to_hex(uint64_t num, uint8_t hex_digits, char *out)
{
int pos;
int string_idx;
uint64_t mask;
if (!out || !hex_digits)
return;
if (hex_digits > 16)
return;
for (pos = hex_digits - 1, string_idx = 0; pos >= 0; pos--, string_idx++) {
mask = num & ((uint64_t)0xFULL << (pos * 4));
mask >>= pos * 4;
if (mask <= 0x9) {
out[string_idx] = 0x30 + (char)mask;
} else if (mask > 0x9) {
out[string_idx] = 0x37 + mask;
}
}
}
static void create_sn_from_unique_id(void)
{
uint64_t lot;
uint32_t uid;
char id_string[25];
int i;
int j;
struct usb_descriptor_entry *desc_entry;
unique_id_get(&lot, &uid);
uint_to_hex(lot, 16, id_string);
id_string[16] = ':';
uint_to_hex(uid, 8, &id_string[17]);
for (i = 0; desc_table[i].descriptor; i++) {
desc_entry = &desc_table[i];
if (desc_entry->descriptor == serial_string_desc) {
for (j = 0; j < 25; j++) {
serial_string_desc[2 * j + 2] = id_string[j];
serial_string_desc[2 * j + 1 + 2] = 0x00;
}
desc_entry->size = 25 * 2 + 2;
serial_string_desc[0] = 25 * 2 + 2;
serial_string_desc[1] = 3;
break;
}
}
}
bool expect_report;
bool expect_eeprom_data;
uint16_t eep_offset;
uint16_t eep_len;
static void ep_rx_data_callback(uint8_t endpoint, const uint8_t *buffer, uint32_t len)
{
if (endpoint == 0) {
if (expect_report) {
usb_endpoint_send_status_stage(0);
} else if (expect_eeprom_data) {
if (len > eep_len) {
usb_endpoint_stall(0, true, true);
} else {
data_eeprom_write(eep_offset, buffer, len);
eep_len -= len;
eep_offset += len;
if (eep_len == 0) {
usb_endpoint_send_status_stage(0);
}
}
}
}
return;
}
static void append_pedal_keycodes_to_report(struct hid_report *r, uint32_t word)
{
int i, j;
uint8_t keycode;
if (word & 0xFF) {
r->modifier |= word & 0xFF;
}
for (i = 0; i < 3; i++) {
word >>= 8;
keycode = word & 0xFF;
if (!keycode)
continue;
for (j = 0; j < 6; j++) {
if (r->keycodes[j] == 0) {
r->keycodes[j] = keycode;
break;
}
}
}
}
static void build_report(struct hid_report *r)
{
uint32_t idr;
const uint32_t *pedal1_word = (const uint32_t *)0x08080000UL;
const uint32_t *pedal2_word = (const uint32_t *)0x08080004UL;
idr = GPIOB->IDR;
memset(r, 0, sizeof(struct hid_report));
if (!(idr & (1<<7))) {
append_pedal_keycodes_to_report(r, *pedal1_word);
}
if (!(idr & (1<<6))) {
append_pedal_keycodes_to_report(r, *pedal2_word);
}
}
static uint16_t idle;
static enum control_state ep_rx_setup_received_callback(uint8_t endpoint, const struct setup_packet *setup_pkg)
{
enum control_state ret_state = CONTROL_NOT_HANDLED;
static struct hid_report r;
expect_report = false;
expect_eeprom_data = false;
eep_len = 0;
eep_offset = 0;
if (endpoint != 0) {
return ret_state;
}
if (setup_pkg->bm_req_type & 0x80) {
/* Device to host transfer */
if ((setup_pkg->bm_req_type & 0xE0) == 0x20) {
/* Class transfer */
switch (setup_pkg->b_request) {
case 0x01:
/* Get report */
build_report(&r);
usb_endpoint_send(0, (uint8_t *)&r, sizeof(r));
ret_state = CONTROL_DATA_TX;
break;
case 0x02:
/* Get idle */
usb_endpoint_send(0, (uint8_t *)&idle, 2);
break;
}
} else if (setup_pkg->bm_req_type & (1<<6)) {
switch (setup_pkg->b_request) {
case 0x2:
usb_endpoint_send(0, (uint8_t *)0x08080000, setup_pkg->w_length);
ret_state = CONTROL_DATA_TX;
break;
}
}
} else {
/* Host to device transfer */
if ((setup_pkg->bm_req_type & 0xE0) == 0x20) {
/* Class transfer */
switch (setup_pkg->b_request) {
case 0xA:
/* Set idle */
idle = setup_pkg->w_value;
ret_state = CONTROL_STATUS_TX;
break;
case 0x09:
/* Set report */
expect_report = true;
usb_endpoint_prepare_receive(0, ep0_buff, sizeof(ep0_buff));
ret_state = CONTROL_DATA_RX;
break;
default:
break;
}
} else if (setup_pkg->bm_req_type == 0x1 && setup_pkg->b_request == 11) {
/* Set interface */
/* Nothing to do. Just ack it */
ret_state = CONTROL_STATUS_TX;
} else if (setup_pkg->bm_req_type == (1<<6)) {
/* Vendor Access */
switch (setup_pkg->b_request) {
case 0x1:
if (setup_pkg->w_value)
GPIOA->ODR |= (1<<setup_pkg->w_index);
else
GPIOA->ODR &= ~(1<<setup_pkg->w_index);
ret_state = CONTROL_STATUS_TX;
break;
case 0x2:
expect_eeprom_data = true;
eep_len = setup_pkg->w_length;
eep_offset = setup_pkg->w_index;
usb_endpoint_prepare_receive(0, ep0_buff, sizeof(ep0_buff));
ret_state = CONTROL_DATA_RX;
break;
default:
break;
}
}
}
return ret_state;
}
static volatile bool ep1_tx_pending;
static void ep_tx_complete_callback(uint8_t endpoint)
{
if (endpoint == 1) {
ep1_tx_pending = false;
} else if (endpoint == 0) {
}
}
static void usb_sof_callback(void)
{
}
static volatile bool configured = false;
static void usb_reset_callback(void)
{
configured = false;
}
static void usb_configured_callback(uint16_t config_idx)
{
GPIOA->ODR &= ~0xF;
usb_endpoint_config(EP_INTERRUPT, 1, false, true);
configured = true;
}
const struct usb_callbacks my_callbacks = {
.ep_rx_data_callback = ep_rx_data_callback,
.ep_rx_setup_received_callback = ep_rx_setup_received_callback,
.ep_tx_complete_callback = ep_tx_complete_callback,
.usb_configured_callback = usb_configured_callback,
.usb_reset_callback = usb_reset_callback,
.usb_sof_callback = usb_sof_callback,
};
static void patch_vid_pid()
{
const uint32_t * const vid_pid_ptr = (const uint32_t *)0x08080008;
const uint32_t vid_pid_word = *vid_pid_ptr;
uint16_t vid;
uint16_t pid;
vid = (vid_pid_word >> 16) & 0xFFFFU;
pid = vid_pid_word & 0xFFFF;
if (vid != 0U && pid != 0U) {
dev_descriptor[8] = (uint8_t)(vid & 0xFF);
dev_descriptor[9] = (uint8_t)((vid >> 8) & 0xFF);
dev_descriptor[10] = (uint8_t)(pid & 0xFF);
dev_descriptor[11] = (uint8_t)((pid >> 8) & 0xFF);
}
}
int main(void)
{
bool status_changed = false;
struct hid_report report;
struct hid_report report_send_buff;
RCC->IOPENR |= RCC_IOPENR_IOPAEN;
GPIOA->MODER &= ~(3<<(0*2)) & ~(3<<(1*2)) & ~(3<<(2*2)) & ~(3<<(3*2));
GPIOA->MODER |= (1<<(0*2)) | (1<<(1*2)) | (1<<(2*2)) | (1<<(3*2));
GPIOA->ODR |= (1<<0);
SysTick_Config(3200000);
//setup_usb_clock();
__enable_irq();
create_sn_from_unique_id();
patch_vid_pid();
usb_init(&my_callbacks);
wait_for_ticks(2);
usb_enable(desc_table);
NVIC_SetPriority(SysTick_IRQn, 0);
NVIC_SetPriority(USB_IRQn, 1);
RCC->IOPENR |= RCC_IOPENR_GPIOBEN;
GPIOB->MODER &= ~((0x3<<(6*2)) | (0x3<<(7*2)));
GPIOB->PUPDR |= (1<<(6*2)) | (1<<(7*2));
while (1) {
while (!configured) {
ep1_tx_pending = false;
}
build_report(&report);
if (memcmp(&report, &report_send_buff, sizeof(struct hid_report)))
status_changed = true;
if (status_changed && !ep1_tx_pending) {
memcpy(&report_send_buff, &report, sizeof(struct hid_report));
ep1_tx_pending = true;
status_changed = false;
usb_endpoint_send(1, (uint8_t *)&report_send_buff, sizeof(struct hid_report));
}
}
}
void SysTick_Handler(void)
{
tick++;
}

View File

@ -0,0 +1,74 @@
/*
* STM32L052x8 System Setup Code
*
* This file is part of 'STM32L052' code template'.
*
* It 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, version 2 of the License.
*
* This code 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 template. If not, see <http://www.gnu.org/licenses/>.
* ------------------------------------------------------------------------
*/
#include <stm32l0xx.h>
#include <stdint.h>
/**
* @brief Init for 32 MHz clock
*/
static void __init_default_clocks(void)
{
uint32_t tmp;
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
/* Set Flash Waitstate */
FLASH->ACR |= FLASH_ACR_LATENCY;
/* Configure interal voltage regualtor to range 1 (1.8V) */
PWR->CR = PWR_CR_VOS_0;
/* Enable MSI osc as main source for now to ensure we're running stable */
tmp = RCC->CFGR;
tmp &= ~0x3;
RCC->CFGR = tmp;
/* Enable HSI */
RCC->CR |= RCC_CR_HSION;
/* Wait for HSI to be ready */
while (!(RCC->CR & RCC_CR_HSIRDY));
/* Disable PLL */
RCC->CR &= ~RCC_CR_PLLON;
while (RCC->CR & RCC_CR_PLLRDY);
/* Reset PLL and clock div config etc. */
RCC->CFGR = 0;
/* Configure PLL for HSI input and 32 MHz output
* PLLDIV = 2
* PLLMUL = x4
*/
RCC->CFGR |= RCC_CFGR_PLLDIV_0 | RCC_CFGR_PLLMUL_0;
/* Startup PLL */
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY));
/* Switch over to PLL clock. Prescalers for buses are finde with div by 1 for 32 MHz */
RCC->CFGR |= RCC_CFGR_SW_0 | RCC_CFGR_SW_1;
}
void __system_init(void)
{
__init_default_clocks();
}

View File

@ -0,0 +1,199 @@
/*
* STM32L052x8 Startup code
*
* This file is part of 'STM32L052' code template'.
*
* It 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, version 2 of the License.
*
* This code 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 template. If not, see <http://www.gnu.org/licenses/>.
* ------------------------------------------------------------------------
*/
/* C++ library init */
# if defined(__cplusplus)
extern "C" {
extern void __libc_init_array(void);
}
#endif
/* Defines for weak default handlers */
#define WEAK __attribute__((weak))
#define ALIAS(func) __attribute__ ((weak, alias (#func)))
/* Define for section mapping */
#define SECTION(sec) __attribute__((section(sec)))
/* Handler prototypes */
#if defined(_cplusplus)
extern "C" {
#endif
/* Interrupt Default handler */
WEAK void __int_default_handler(void);
/* Core Interrupts */
void Reset_Handler(void);
void NMI_Handler(void) ALIAS(__int_default_handler);
void HardFault_Handler(void) ALIAS(__int_default_handler);
void SVCall_Handler(void) ALIAS(__int_default_handler);
void PendSV_Handler(void) ALIAS(__int_default_handler);
void SysTick_Handler(void) ALIAS(__int_default_handler);
/* Peripheral Interrupts (by default mapped onto Default Handler) */
void WWDG_IRQHandler(void) ALIAS(__int_default_handler);
void PVD_IRQHandler(void) ALIAS(__int_default_handler);
void RTC_IRQHandler(void) ALIAS(__int_default_handler);
void FLASH_IRQHandler(void) ALIAS(__int_default_handler);
void RCC_CRS_IRQHandler(void) ALIAS(__int_default_handler);
void EXTI0_1_IRQHandler(void) ALIAS(__int_default_handler);
void EXTI2_3_IRQHandler(void) ALIAS(__int_default_handler);
void EXTI4_15_IRQHandler(void) ALIAS(__int_default_handler);
void TSC_IRQHandler(void) ALIAS(__int_default_handler);
void DMA1_CH1_IRQHandler(void) ALIAS(__int_default_handler);
void DMA1_CH2_3_IRQHandler(void) ALIAS(__int_default_handler);
void DMA1_CH4_5_6_7_IRQHandler(void) ALIAS(__int_default_handler);
void ADC_COMP_IRQHandler(void) ALIAS(__int_default_handler);
void LPTIM1_IRQHandler(void) ALIAS(__int_default_handler);
void USART4_5_IRQHandler(void) ALIAS(__int_default_handler);
void TIM2_IRQHandler(void) ALIAS(__int_default_handler);
void TIM3_IRQHandler(void) ALIAS(__int_default_handler);
void TIM6_DAC_IRQHandler(void) ALIAS(__int_default_handler);
void TIM7_IRQHandler(void) ALIAS(__int_default_handler);
void TIM21_IRQHandler(void) ALIAS(__int_default_handler);
void I2C3_IRQHandler(void) ALIAS(__int_default_handler);
void TIM22_IRQHandler(void) ALIAS(__int_default_handler);
void I2C1_IRQHandler(void) ALIAS(__int_default_handler);
void I2C2_IRQHandler(void) ALIAS(__int_default_handler);
void SPI1_IRQHandler(void) ALIAS(__int_default_handler);
void SPI2_IRQHandler(void) ALIAS(__int_default_handler);
void USART1_IRQHandler(void) ALIAS(__int_default_handler);
void USART2_IRQHandler(void) ALIAS(__int_default_handler);
void LPUART1_AES_RNG_IRQHandler(void) ALIAS(__int_default_handler);
void USB_IRQHandler(void) ALIAS(__int_default_handler);
extern int main(void);
extern void __system_init(void);
extern void __ld_top_of_stack(void);
#if defined(_cplusplus)
extern "C" }
#endif
void (* const vector_table[])(void) SECTION(".vectors") = {
&__ld_top_of_stack,
/* Core Interrupts */
Reset_Handler,
NMI_Handler,
HardFault_Handler,
0,
0,
0,
0,
0,
0,
0,
SVCall_Handler,
0,
0,
PendSV_Handler,
SysTick_Handler,
/* Peripheral Interrupts */
WWDG_IRQHandler,
PVD_IRQHandler,
RTC_IRQHandler,
FLASH_IRQHandler,
RCC_CRS_IRQHandler,
EXTI0_1_IRQHandler,
EXTI2_3_IRQHandler,
EXTI4_15_IRQHandler,
TSC_IRQHandler,
DMA1_CH1_IRQHandler,
DMA1_CH2_3_IRQHandler,
DMA1_CH4_5_6_7_IRQHandler,
ADC_COMP_IRQHandler,
LPTIM1_IRQHandler,
USART4_5_IRQHandler,
TIM2_IRQHandler,
TIM3_IRQHandler,
TIM6_DAC_IRQHandler,
TIM7_IRQHandler,
0,
TIM21_IRQHandler,
I2C3_IRQHandler,
TIM22_IRQHandler,
I2C1_IRQHandler,
I2C2_IRQHandler,
SPI1_IRQHandler,
SPI2_IRQHandler,
USART1_IRQHandler,
USART2_IRQHandler,
LPUART1_AES_RNG_IRQHandler,
0,
USB_IRQHandler,
};
static void __init_section(unsigned int *src_start, unsigned int *dest_start, unsigned int *dest_end) {
unsigned int *get, *put;
put = dest_start;
get = src_start;
while ((unsigned int)put < (unsigned int)dest_end) {
*(put++) = *(get++);
}
}
static void __fill_zero(unsigned int *start, unsigned int *end) {
while ((unsigned int) start < (unsigned int)end) {
*(start++) = 0x00000000;
}
}
extern unsigned int __ld_load_data;
extern unsigned int __ld_sitcm;
extern unsigned int __ld_eitcm;
extern unsigned int __ld_sdtcm;
extern unsigned int __ld_edtcm;
extern unsigned int __ld_sdata;
extern unsigned int __ld_edata;
extern unsigned int __ld_sbss;
extern unsigned int __ld_ebss;
extern unsigned int __ld_sheap;
extern unsigned int __ld_eheap;
void Reset_Handler(void) {
/* Stack is already initilized by hardware */
/* Copy .data section */
__init_section(&__ld_load_data, &__ld_sdata, &__ld_edata);
/* Fill bss with zero */
__fill_zero(&__ld_sbss, &__ld_ebss);
/* Fill Heap with zero */
__fill_zero(&__ld_sheap, &__ld_eheap);
/* Set clocks, waitstates, ART operation etc. */
__system_init();
/* C++ init function */
#if defined(__cplusplus)
__libc_init_array();
#endif
/* Call main */
main();
/* Catch return from main() */
while(1);
}
WEAK void __int_default_handler(void)
{
while(1);
}

View File

@ -0,0 +1,142 @@
/*
* STM32L052x8 Linkerscript
*
* This file is part of 'STM32L052' code template'.
*
* It 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, version 2 of the License.
*
* This code 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 template. If not, see <http://www.gnu.org/licenses/>.
* ------------------------------------------------------------------------
*
* Flash Size: 64kB
* RAM Size: 8kB
*/
/* USER PARAMETERS */
__ld_stack_size = 0x0400;
__ld_heap_size = 0x0200;
/* END OF USER PARAMETERS */
ENTRY(Reset_Handler)
__ld_top_of_stack = 0x20001000; /* One byte above the end of the SRAM. Stack is pre-decrewmenting, so this is okay */
/* Available memory areas */
MEMORY
{
FLASH (xr) : ORIGIN = 0x08000000, LENGTH = 64K
EEPROM (r) : ORIGIN = 0x08080000, LENGTH = 2K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K
}
SECTIONS
{
.vectors : ALIGN(4)
{
KEEP(*(.vectors))
. = ALIGN(4);
} >FLASH
.text : ALIGN(4)
{
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP(*(.init)) /* Constructors */
KEEP(*(.fini)) /* Destructors */
. = ALIGN(4);
} >FLASH
.ARM.extab : ALIGN(4)
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH
.ARM : ALIGN(4)
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
. = ALIGN(4);
} >FLASH
/* Constructor/Destructor tables */
.preinit_array : ALIGN(4)
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
} >FLASH
.init_array : ALIGN(4)
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH
.fini_array : ALIGN(4)
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
} >FLASH
.eeprom (NOLOAD) : ALIGN(4)
{
__ld_seeprom = .;
*(.eepdata)
*(.eepdata*)
} >EEPROM
/* Initialized Data */
__ld_load_data = LOADADDR(.data);
.data : ALIGN(4)
{
__ld_sdata = .;
*(.data)
*(.data*)
. = ALIGN(4);
__ld_edata = .;
} >RAM AT> FLASH
/* Uninitialized static data */
.bss : ALIGN(4)
{
__ld_sbss = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__ld_ebss = .;
} >RAM
.heap_stack (NOLOAD) : ALIGN(4)
{
__ld_sheap = .;
. = . + __ld_heap_size;
__ld_eheap = .;
. = . + __ld_stack_size;
. = ALIGN(4);
} >RAM
}

16671
firmware/svd/STM32L0x1.svd Normal file

File diff suppressed because it is too large Load Diff

20698
firmware/svd/STM32L0x2.svd Normal file

File diff suppressed because it is too large Load Diff

22518
firmware/svd/STM32L0x3.svd Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
extern char __ld_sheap; // Defined by the linker
extern char __ld_eheap;
char* _sbrk(int incr) {
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0) {
heap_end = &__ld_sheap;
}
prev_heap_end = heap_end;
if (heap_end + incr > &__ld_eheap) {
return 0;
}
heap_end += incr;
return (char*) prev_heap_end;
}
int _isatty(int fd) {
return 1;
}
int _close(int fd) {
return 0;
}
int _open(int fd) {
return 0;
}
int _fstat(void) {
return 0;
}
int _lseek(void) {
return 0;
}
int _read(void) {
return 0;
}
int _write(int fd, const void *buf, int count) {
//sendString((char*)buf, count);
return count;
}

11
firmware/unique-id.c Normal file
View File

@ -0,0 +1,11 @@
#include "unique-id.h"
#define UNIQUE_ID_BASE_ADDR 0x1FF80050UL
void unique_id_get(uint64_t *lot_wafer_number, uint32_t *unique_number)
{
if (lot_wafer_number)
*lot_wafer_number = *((uint64_t *)UNIQUE_ID_BASE_ADDR);
if (unique_number)
*unique_number = *((uint32_t *)(UNIQUE_ID_BASE_ADDR + 0x14UL));
}

8
firmware/unique-id.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _UNIQUE_ID_H_
#define _UNIQUE_ID_H_
#include <stdint.h>
void unique_id_get(uint64_t *lot_wafer_number, uint32_t *unique_number);
#endif /* _UNIQUE_ID_H_ */

668
firmware/usb.c Normal file
View File

@ -0,0 +1,668 @@
#include "usb.h"
#include <stm32l0xx.h>
#include <stddef.h>
#define ENDPOINT_COUNT (8)
enum endpoint_state {EP_STATE_DISABLED, EP_STATE_NAK, EP_STATE_STALL, EP_STATE_VALID};
static void (*ep_rx_data_callback)(uint8_t endpoint, const uint8_t *buffer, uint32_t len) = NULL;
static enum control_state (*ep_rx_setup_received_callback)(uint8_t endpoint, const struct setup_packet *setup_pkg) = NULL;
static void (*ep_tx_complete_callback)(uint8_t endpoint);
static void (*usb_sof_callback)(void) = NULL;
static void (*usb_reset_callback)(void) = NULL;
static void (*usb_configured_callback)(uint16_t config_idx) = NULL;
struct usb_endpoint_info {
uint16_t rx_pma_size;
uint16_t tx_pma_size;
enum usb_ep_type type;
struct setup_packet last_setup;
enum control_state ctrl_state;
volatile uint16_t *ep_reg;
uint32_t tx_count;
const uint8_t *tx_ptr;
uint32_t rx_size;
uint8_t *rx_buffer;
};
static const struct usb_descriptor_entry *usb_descriptors = NULL;
static uint16_t * const pma_base_ptr = (uint16_t *)0x40006000UL;
struct usb_endpoint_info endpoints[ENDPOINT_COUNT];
static void setup_usb_clock(void)
{
uint32_t reload_val;
const uint32_t felim = 0x22;
const uint32_t f_target = 48000000UL;
const uint32_t f_usb_sof = 1000UL;
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
/* Enable the internal voltage reference. This is needed for HSI48 */
SYSCFG->CFGR3 |= SYSCFG_CFGR3_EN_VREFINT;
while (!(SYSCFG->CFGR3 & SYSCFG_CFGR3_VREFINT_RDYF));
SYSCFG->CFGR3 |= SYSCFG_CFGR3_ENREF_HSI48;
RCC->CRRCR = RCC_CRRCR_HSI48ON;
while(!(RCC->CRRCR & RCC_CRRCR_HSI48RDY));
RCC->CCIPR |= RCC_CCIPR_HSI48SEL;
/* Configure Clock recovery from USB SOF (1kHz) */
RCC->APB1ENR |= RCC_APB1ENR_CRSEN;
reload_val = (f_target / f_usb_sof) - 1;
CRS->CFGR = (reload_val & 0xFFFF) | (felim << 16) | CRS_CFGR_SYNCSRC_1;
CRS->CR = CRS_CR_CEN | CRS_CR_AUTOTRIMEN;
}
void usb_init(const struct usb_callbacks *callbacks)
{
setup_usb_clock();
/* Activate register clock for USB */
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
/* Power up the USB interface but hold in reset */
USB->CNTR = USB_CNTR_FRES;
endpoints[0].ep_reg = &USB->EP0R;
endpoints[1].ep_reg = &USB->EP1R;
endpoints[2].ep_reg = &USB->EP2R;
endpoints[3].ep_reg = &USB->EP3R;
endpoints[4].ep_reg = &USB->EP4R;
endpoints[5].ep_reg = &USB->EP5R;
endpoints[6].ep_reg = &USB->EP6R;
endpoints[7].ep_reg = &USB->EP7R;
/* Setup the callbacks */
ep_rx_data_callback = callbacks->ep_rx_data_callback;
ep_tx_complete_callback = callbacks->ep_tx_complete_callback;
ep_rx_setup_received_callback = callbacks->ep_rx_setup_received_callback;
usb_configured_callback = callbacks->usb_configured_callback;
usb_reset_callback = callbacks->usb_reset_callback;
usb_sof_callback = callbacks->usb_sof_callback;
}
static void write_b_table(uint32_t addr, uint16_t value)
{
volatile uint16_t *ptr = pma_base_ptr;
ptr += (addr >> 1);
*ptr = value;
}
static uint16_t read_b_table(uint32_t addr)
{
volatile uint16_t *ptr = pma_base_ptr;
ptr += (addr >> 1);
return *ptr;
}
static uint16_t read_rx_pma(uint8_t ep, uint8_t *buff, uint32_t size)
{
uint16_t rx_btable_entry;
uint16_t pma_addr;
uint8_t *app_addr;
uint16_t count;
uint16_t i;
rx_btable_entry = read_b_table(ep * 8 + 6);
count = rx_btable_entry & 0x3FF;
pma_addr = read_b_table(ep * 8 + 4);
app_addr = (uint8_t *)pma_base_ptr;
app_addr += (pma_addr >> 0);
/* Byte addresed writes seem to work just fine */
for (i = 0; i < count && i < size; i++) {
buff[i] = app_addr[i];
}
return count;
}
static void write_tx_pma(uint8_t ep, const uint8_t *src, uint32_t len)
{
uint16_t tx_addr;
uint16_t *pma = pma_base_ptr;
uint32_t i;
uint32_t halfword_cnt;
bool padding;
write_b_table(ep * 8 + 2, len);
if (!len)
return;
tx_addr = read_b_table(ep * 8);
padding = len % 2 ? true : false;
halfword_cnt = len >> 1;
pma += tx_addr >> 1;
for (i = 0; i < halfword_cnt; i++) {
pma[i] = (uint16_t)src[2 * i] | (((uint16_t)src[2 * i + 1]) << 8);
}
if (padding) {
pma[i] = (uint16_t)src[2 * i];
}
}
static const struct usb_descriptor_entry *find_descriptor_from_setup_request(uint16_t w_index, uint16_t w_value)
{
int i;
const struct usb_descriptor_entry *entry = NULL;
for (i = 0; usb_descriptors[i].descriptor != NULL; i++) {
if (usb_descriptors[i].w_index == w_index && usb_descriptors[i].w_value == w_value) {
entry = &usb_descriptors[i];
break;
}
}
return entry;
}
void usb_endpoint_config(enum usb_ep_type type, uint8_t epnum, bool rx, bool tx)
{
uint16_t epreg = 0;
struct usb_endpoint_info *ep_info;
if (epnum >= ENDPOINT_COUNT)
return;
ep_info = &endpoints[epnum];
write_b_table(epnum * 8 + 0, 64 + epnum * 136);
write_b_table(epnum * 8 + 2, 0);
write_b_table(epnum * 8 + 4, 64 + epnum * 136 + 72);
write_b_table(epnum * 8 + 6, (1 << 10) | (1<<15));
epreg = *ep_info->ep_reg;
epreg &= ~(1<<15);
switch (type) {
case EP_CONTROL:
epreg |= (1<<9);
ep_info->type = EP_CONTROL;
ep_info->ctrl_state = CONTROL_SETUP;
ep_info->tx_pma_size = 64;
ep_info->rx_pma_size = 64;
case EP_BULK:
ep_info->type = EP_BULK;
ep_info->ctrl_state = CONTROL_SETUP;
ep_info->tx_pma_size = 64;
ep_info->rx_pma_size = 64;
break;
case EP_INTERRUPT:
epreg |= (1<<10) | (1<<9);
ep_info->type = EP_INTERRUPT;
ep_info->ctrl_state = CONTROL_SETUP;
ep_info->tx_pma_size = 64;
ep_info->rx_pma_size = 64;
break;
case EP_ISOCHRON:
epreg |= (1<<10);
ep_info->type = EP_ISOCHRON;
ep_info->ctrl_state = CONTROL_SETUP;
ep_info->tx_pma_size = 64;
ep_info->rx_pma_size = 64;
break;
default:
return;
break;
}
if (tx) {
epreg |= (1<<5);
}
if (rx) {
epreg |= (1<<13);
}
epreg |= epnum;
*ep_info->ep_reg = epreg;
}
static void usb_endpoint_reset_int_flags(uint8_t endpoint, bool rx, bool tx)
{
uint16_t ep_reg;
if (endpoint >= ENDPOINT_COUNT)
return;
ep_reg = *endpoints[endpoint].ep_reg;
ep_reg &= ~((1<<14) | (1<<6) | (1<<5) | (1<<13) | (1<<12) | (1<<4));
/* Dont clear flag */
if (rx) {
ep_reg &= ~(1<<15);
} else {
ep_reg |= (1<<15);
}
if (tx) {
ep_reg &= ~(1<<7);
} else {
ep_reg |= (1<<7);
}
*endpoints[endpoint].ep_reg = ep_reg;
}
static void usb_endpoint_set_rx_state(uint8_t endpoint, enum endpoint_state state)
{
uint16_t ep_reg;
uint16_t ep_rx_target = 0;
if (endpoint >= ENDPOINT_COUNT)
return;
ep_reg = *endpoints[endpoint].ep_reg;
/* Mask out all toggle flags that we don't want to change */
ep_reg &= ~((1<<14) | (1<<6) | (1<<5) | (1<<4));
/* Dont clear flag */
ep_reg |= (1<<15) | (1<<7);
/* Prepare the target value */
switch (state) {
case EP_STATE_DISABLED:
ep_rx_target = 0;
break;
case EP_STATE_NAK:
ep_rx_target = (1<<13);
break;
case EP_STATE_VALID:
ep_rx_target = (1<<13) | (1<<12);
break;
case EP_STATE_STALL:
ep_rx_target = (1<<12);
default:
return;
}
/* Generate toggle mask for the TX bits */
ep_reg ^= ep_rx_target;
*endpoints[endpoint].ep_reg = ep_reg;
}
static void usb_endpoint_set_tx_state(uint8_t endpoint, enum endpoint_state state)
{
uint16_t ep_reg;
uint16_t ep_tx_target = 0;
if (endpoint >= ENDPOINT_COUNT)
return;
ep_reg = *endpoints[endpoint].ep_reg;
/* Mask out all toggle flags that we don't want to change */
ep_reg &= ~((1<<14) | (1<<13) | (1<<12) | (1<<6));
/* Dont clear flag */
ep_reg |= (1<<15) | (1<<7);
/* Prepare the target value */
switch (state) {
case EP_STATE_DISABLED:
ep_tx_target = 0;
break;
case EP_STATE_NAK:
ep_tx_target = (1<<5);
break;
case EP_STATE_VALID:
ep_tx_target = (1<<5) | (1<<4);
break;
case EP_STATE_STALL:
ep_tx_target = (1<<4);
default:
return;
}
/* Generate toggle mask for the TX bits */
ep_reg ^= ep_tx_target;
*endpoints[endpoint].ep_reg = ep_reg;
}
void usb_endpoint_stall(uint8_t endpoint, bool tx_dir, bool rx_dir)
{
if (tx_dir)
usb_endpoint_set_tx_state(endpoint, EP_STATE_STALL);
}
int usb_endpoint_send(uint8_t endpoint, const uint8_t *data, uint32_t len)
{
struct usb_endpoint_info *epinfo;
uint32_t tx_cnt;
if (endpoint >= ENDPOINT_COUNT)
return -1001;
epinfo = &endpoints[endpoint];
if (epinfo->tx_pma_size == 0)
return -1;
tx_cnt = len < epinfo->tx_pma_size ? len : epinfo->tx_pma_size;
/* Copy data to pma and save the data pointer to the next word to be transmitted */
if (tx_cnt < len) {
epinfo->tx_ptr = &data[tx_cnt];
epinfo->tx_count = len - tx_cnt;
} else {
epinfo->tx_count = 0;
epinfo->tx_ptr = NULL;
}
write_tx_pma(endpoint, data, tx_cnt);
/* Prepare endpoint for TX */
usb_endpoint_set_tx_state(endpoint, EP_STATE_VALID);
return 0;
}
int usb_endpoint_prepare_receive(uint8_t endpoint, uint8_t *buffer, uint32_t bufflen)
{
struct usb_endpoint_info *info;
if (endpoint >= ENDPOINT_COUNT)
return -1001;
info = &endpoints[endpoint];
if (info->rx_buffer || info->rx_size) {
return -1;
}
__disable_irq();
info->rx_buffer = buffer;
info->rx_size = bufflen;
usb_endpoint_set_rx_state(endpoint, EP_STATE_VALID);
__enable_irq();
return 0;
}
void usb_endpoint_send_status_stage(uint8_t endpoint)
{
struct usb_endpoint_info *info;
if (endpoint >= ENDPOINT_COUNT)
return;
info = &endpoints[endpoint];
info->ctrl_state = CONTROL_STATUS_TX;
usb_endpoint_send(endpoint, NULL, 0);
}
void usb_enable(const struct usb_descriptor_entry *descriptors)
{
if (!descriptors)
return;
usb_descriptors = descriptors;
/* Enable device with address 0 */
USB->DADDR = USB_DADDR_EF;
/* Clear all interrupts */
USB->ISTR = 0;
/* Set buffer description table to beginning of PMA */
USB->BTABLE = 0x0U;
/* Actiovate USB module (clear reset bit) and setup the interrupt masks */
USB->CNTR = USB_CNTR_CTRM | USB_CNTR_ERRM | USB_CNTR_RESETM | USB_CNTR_SOFM;
/* Enable internal D+ pullup to tell the host we're here */
USB->BCDR = USB_BCDR_DPPU;
NVIC_EnableIRQ(USB_IRQn);
}
static void usb_handle_reset(void)
{
int i;
/* Reset USB address */
USB->DADDR = USB_DADDR_EF;
for (i = 0; i < ENDPOINT_COUNT; i++) {
endpoints[i].rx_size = 0;
endpoints[i].rx_buffer = NULL;
endpoints[i].tx_count = 0;
endpoints[i].tx_ptr = NULL;
}
usb_endpoint_config(EP_CONTROL, 0, true, true);
usb_endpoint_set_rx_state(0, EP_STATE_VALID);
}
void usb_ep0_send_status(void)
{
struct usb_endpoint_info *ep_info;
ep_info = &endpoints[0];
ep_info->ctrl_state = CONTROL_STATUS_TX;
usb_endpoint_send(0, NULL, 0);
}
void usb_ep0_handle_setup(void)
{
uint16_t cnt;
enum control_state next_state;
const struct usb_descriptor_entry *descriptor;
struct usb_endpoint_info *ep_info;
struct setup_packet *setup;
ep_info = &endpoints[0];
ep_info->ctrl_state = CONTROL_SETUP;
setup = &ep_info->last_setup;
cnt = read_rx_pma(0, (uint8_t *)setup, 8);
if (cnt != 8) {
usb_endpoint_stall(0, true, true);
return;
}
if ((setup->bm_req_type == 0x80 || setup->bm_req_type == 0x81 || setup->bm_req_type == 0x82) && setup->b_request == 6) {
/* Get descriptor request */
descriptor = find_descriptor_from_setup_request(setup->w_index, setup->w_value);
if (!descriptor) {
usb_endpoint_stall(0, true, true);
}
cnt = setup->w_length < descriptor->size ? setup->w_length : descriptor->size;
usb_endpoint_send(0, descriptor->descriptor, cnt);
ep_info->ctrl_state = CONTROL_DATA_TX;
} else if (setup->bm_req_type == 0x00 && setup->b_request == 5) {
/* Set address command
* Send out status stage and set address after status has finished
*/
usb_ep0_send_status();
} else if (setup->bm_req_type == 0x00 && setup->b_request == 9) {
/* Set configuration */
if (usb_configured_callback)
usb_configured_callback(setup->w_value);
usb_ep0_send_status();
} else {
next_state = CONTROL_NOT_HANDLED;
/* Check if the callback for setup requests is set and try to handle it this way */
if (ep_rx_setup_received_callback)
next_state = ep_rx_setup_received_callback(0, setup);
/* We could not handle the setup request if handle state != 0 */
if (next_state == CONTROL_NOT_HANDLED) {
usb_endpoint_stall(0, true, true);
} else {
/* Control handled */
switch (next_state) {
case CONTROL_STATUS_TX:
usb_ep0_send_status();
break;
case CONTROL_DATA_TX:
break;
case CONTROL_DATA_RX:
break;
default:
usb_endpoint_stall(0, true, true);
break;
}
}
ep_info->ctrl_state = (next_state != CONTROL_NOT_HANDLED ? next_state : CONTROL_SETUP);
}
return;
}
void usb_ep0_handle_tx(void)
{
struct usb_endpoint_info *info = &endpoints[0];
if (info->tx_count) {
/* Do the rest */
usb_endpoint_send(0, info->tx_ptr, info->tx_count);
} else {
if (info->ctrl_state == CONTROL_DATA_TX) {
info->ctrl_state = CONTROL_STATUS_RX;
/* Listen for new setup packets */
usb_endpoint_set_rx_state(0, EP_STATE_VALID);
} else if (info->ctrl_state == CONTROL_STATUS_TX) {
/* we've sent a status back. Check if we should set our address now */
if (info->last_setup.bm_req_type == 0x00 && info->last_setup.b_request == 0x5) {
USB->DADDR = USB_DADDR_EF | info->last_setup.w_value;
}
info->ctrl_state = CONTROL_SETUP;
/* Listen for new setup packets */
usb_endpoint_set_rx_state(0, EP_STATE_VALID);
} else {
if (ep_tx_complete_callback)
ep_tx_complete_callback(0);
}
}
}
void usb_handle_rx_packet(uint8_t ep)
{
uint16_t epreg;
struct usb_endpoint_info *info;
uint16_t pkg_len;
uint8_t *buffer;
info = &endpoints[ep];
epreg = *info->ep_reg;
usb_endpoint_reset_int_flags(ep, true, false);
if (epreg & (1<<11) && ep == 0) {
info->ctrl_state = CONTROL_SETUP;
usb_ep0_handle_setup();
} else if (ep == 0 && info->ctrl_state == CONTROL_STATUS_RX) {
info->ctrl_state = CONTROL_SETUP;
/* Check the received status frame */
pkg_len = read_rx_pma(0, NULL, 0);
if (pkg_len != 0) {
usb_endpoint_stall(0, true, true);
} else {
/* Ready to receive next datum */
usb_endpoint_set_rx_state(0, EP_STATE_VALID);
}
} else {
if (epreg & (1<<11)) {
(void)read_rx_pma(ep, (uint8_t *)&info->last_setup, 8);
if (ep_rx_setup_received_callback)
ep_rx_setup_received_callback(ep, &info->last_setup);
}
if (info->rx_buffer && info->rx_size) {
pkg_len = read_rx_pma(ep, info->rx_buffer, info->rx_size);
buffer = info->rx_buffer;
info->rx_size = 0;
info->rx_buffer = 0;
ep_rx_data_callback(ep, buffer, pkg_len);
}
}
}
void usb_handle_tx_packet_sent(uint8_t ep)
{
struct usb_endpoint_info *info = &endpoints[ep];
usb_endpoint_reset_int_flags(ep, false, true);
if (ep == 0) {
usb_ep0_handle_tx();
} else {
if (info->tx_count && info->tx_ptr) {
usb_endpoint_send(ep, info->tx_ptr, info->tx_count);
} else {
if (ep_tx_complete_callback)
ep_tx_complete_callback(ep);
}
}
}
void USB_IRQHandler(void)
{
uint16_t istr = USB->ISTR;
uint8_t endpoint;
bool dir_tx;
if (istr & USB_ISTR_RESET) {
USB->ISTR = (uint16_t)(~USB_ISTR_RESET);
usb_handle_reset();
if (usb_reset_callback)
usb_reset_callback();
}
if (istr & USB_ISTR_CTR) {
/* correct transfer interrupt */
endpoint = istr & USB_ISTR_EP_ID;
dir_tx = (istr & USB_ISTR_DIR) ? false : true;
if (dir_tx) {
usb_handle_tx_packet_sent(endpoint);
} else {
usb_handle_rx_packet(endpoint);
}
/* Clear interrupt */
USB->ISTR = (uint16_t)(~USB_ISTR_CTR);
}
if (istr & USB_ISTR_SOF) {
USB->ISTR = (uint16_t)(~USB_ISTR_SOF);
if (usb_sof_callback)
usb_sof_callback();
}
if (istr & USB_ISTR_ERR) {
USB->ISTR = (uint16_t)(~USB_ISTR_ERR);
}
__DSB();
}

54
firmware/usb.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef _USB_H_
#define _USB_H_
#include <stdint.h>
#include <stdbool.h>
enum control_state {CONTROL_SETUP, CONTROL_DATA_TX, CONTROL_DATA_RX, CONTROL_STATUS_RX, CONTROL_STATUS_TX, CONTROL_NOT_HANDLED};
struct usb_descriptor_entry {
uint16_t w_index;
uint16_t w_value;
const uint8_t *descriptor;
uint32_t size;
};
enum usb_ep_type {
EP_CONTROL,
EP_BULK,
EP_ISOCHRON,
EP_INTERRUPT
};
struct setup_packet {
uint8_t bm_req_type;
uint8_t b_request;
uint16_t w_value;
uint16_t w_index;
uint16_t w_length;
};
struct usb_callbacks {
void (*ep_rx_data_callback)(uint8_t endpoint, const uint8_t *buffer, uint32_t len);
enum control_state (*ep_rx_setup_received_callback)(uint8_t endpoint, const struct setup_packet *setup_pkg);
void (*ep_tx_complete_callback)(uint8_t endpoint);
void (*usb_sof_callback)(void);
void (*usb_reset_callback)(void);
void (*usb_configured_callback)(uint16_t config_idx);
};
void usb_init(const struct usb_callbacks *callbacks);
void usb_enable(const struct usb_descriptor_entry *descriptors);
void usb_endpoint_send_status_stage(uint8_t endpoint);
void usb_endpoint_stall(uint8_t endpoint, bool tx_dir, bool rx_dir);
void usb_endpoint_config(enum usb_ep_type type, uint8_t epnum, bool rx, bool tx);
int usb_endpoint_prepare_receive(uint8_t endpoint, uint8_t *buffer, uint32_t bufflen);
int usb_endpoint_send(uint8_t endpoint, const uint8_t *data, uint32_t len);
#endif /* _USB_H_ */

60
sustain-kbd-config/.gitignore vendored Normal file
View File

@ -0,0 +1,60 @@
# Created by https://www.toptal.com/developers/gitignore/api/c++
# Edit at https://www.toptal.com/developers/gitignore?templates=c++
### C++ ###
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# End of https://www.toptal.com/developers/gitignore/api/c++
# Created by https://www.toptal.com/developers/gitignore/api/cmake
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake
### CMake ###
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
### CMake Patch ###
# External projects
*-prefix/
# End of https://www.toptal.com/developers/gitignore/api/cmake

View File

@ -0,0 +1,74 @@
cmake_minimum_required(VERSION 3.5)
project(sustain-kbd-config VERSION 0.1 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(PkgConfig REQUIRED)
pkg_search_module(LIBUSB REQUIRED libusb-1.0)
# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check https://doc.qt.io/qt/deployment-android.html for more information.
# They need to be set before the find_package( ...) calls below.
#if(ANDROID)
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
# if (ANDROID_ABI STREQUAL "armeabi-v7a")
# set(ANDROID_EXTRA_LIBS
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
# endif()
#endif()
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
set(PROJECT_SOURCES
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
libusbwrapper.cpp
libusbwrapper.h
sustainpedalkeyboard.h
sustainpedalkeyboard.cpp
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(sustain-kbd-config
MANUAL_FINALIZATION
${PROJECT_SOURCES}
)
else()
if(ANDROID)
add_library(sustain-kbd-config SHARED
${PROJECT_SOURCES}
)
else()
add_executable(sustain-kbd-config
${PROJECT_SOURCES}
)
endif()
endif()
target_link_libraries(sustain-kbd-config PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${LIBUSB_LDFLAGS})
target_include_directories(${PROJECT_NAME} PRIVATE ${LIBUSB_INCLUDE_DIRS})
set_target_properties(sustain-kbd-config PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
CXX_STANDARD 17
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(sustain-kbd-config)
endif()

View File

@ -0,0 +1,137 @@
#include "libusbwrapper.h"
#include <libusb.h>
#include <iostream>
UsbDevice::UsbDevice(libusb_device *device)
{
int res;
this->dev = device;
res = libusb_get_device_descriptor(device, &this->devdesc);
this->device_handle = nullptr;
if (res == 0) {
this->vendor_id = devdesc.idVendor;
this->product_id = devdesc.idProduct;
}
}
UsbDevice::UsbDevice(UsbDevice &&d)
{
vendor_id = std::move(d.vendor_id);
product_id = std::move(d.product_id);
dev = d.dev;
devdesc = d.devdesc;
device_handle = std::move(d.device_handle);
}
UsbDevice::~UsbDevice()
{
/* Nothing to do here. Our device handle will be automatically closed once the shared pointer is released */
}
std::vector<UsbDevice> UsbDevice::find_devices(uint16_t vendor_id, uint16_t product_id)
{
auto ret_vector = std::vector<UsbDevice>();
libusb_device **devlist;
int res = libusb_get_device_list(NULL, &devlist);
if (res > 0) {
for (int idx = 0; idx < res; idx++) {
auto d = UsbDevice(devlist[idx]);
if (d.get_product_id() == product_id && d.get_vendor_id() == vendor_id)
ret_vector.push_back(std::move(d));
}
}
return ret_vector;
}
bool UsbDevice::opened()
{
return !!(this->device_handle != nullptr);
}
int UsbDevice::open()
{
int ret;
libusb_device_handle *handle;
if (this->dev) {
ret = libusb_open(this->dev, &handle);
} else {
handle = libusb_open_device_with_vid_pid(NULL, this->vendor_id, this->product_id);
if (!handle)
ret = -1;
else
ret = 0;
}
device_handle = std::make_shared<UsbDeviceHandle>(handle);
return ret;
}
uint16_t UsbDevice::get_vendor_id()
{
return this->vendor_id;
}
uint16_t UsbDevice::get_product_id()
{
return this->product_id;
}
int UsbDevice::control_transfer(uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data, uint16_t wLength, unsigned int timeout)
{
if (!opened())
return -1000;
return libusb_control_transfer(this->device_handle->m_handle, request_type, bRequest, wValue, wIndex, data, wLength, timeout);
}
const std::string &UsbDevice::get_serial_number()
{
char buffer[256] = {0};
if (!opened())
return serial;
if (devdesc.iSerialNumber == 0)
return serial;
if (serial.length() > 0) {
return serial;
}
int res = libusb_get_string_descriptor_ascii(device_handle->m_handle, devdesc.iSerialNumber, (unsigned char *)buffer, 255);
if (res > 0) {
serial = std::string(buffer);
return serial;
} else {
return serial;
}
}
void LibUsbInit()
{
libusb_init(NULL);
}
void LibUsbDeInit()
{
libusb_exit(NULL);
}
UsbDeviceHandle::UsbDeviceHandle(libusb_device_handle *handle)
{
m_handle = handle;
}
UsbDeviceHandle::~UsbDeviceHandle()
{
if (m_handle)
libusb_close(m_handle);
m_handle = NULL;
}

View File

@ -0,0 +1,47 @@
#ifndef LIBUSBWRAPPER_H
#define LIBUSBWRAPPER_H
#include <stdint.h>
#include <vector>
#include <string>
#include <libusb.h>
#include <memory>
void LibUsbInit();
void LibUsbDeInit();
class UsbDeviceHandle {
public:
UsbDeviceHandle(libusb_device_handle *handle);
~UsbDeviceHandle();
libusb_device_handle *m_handle;
};
class UsbDevice {
public:
UsbDevice(libusb_device *device);
UsbDevice(const UsbDevice &d) = default;
UsbDevice(UsbDevice &&d);
~UsbDevice();
static std::vector<UsbDevice> find_devices(uint16_t vendor_id, uint16_t product_id);
bool opened();
int open();
uint16_t get_vendor_id();
uint16_t get_product_id();
int control_transfer(uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
unsigned char *data, uint16_t wLength, unsigned int timeout);
const std::string &get_serial_number();
private:
std::shared_ptr<UsbDeviceHandle> device_handle;
libusb_device *dev;
uint16_t vendor_id;
uint16_t product_id;
std::string serial;
struct libusb_device_descriptor devdesc;
};
#endif // LIBUSBWRAPPER_H

View File

@ -0,0 +1,23 @@
#include "mainwindow.h"
#include "libusbwrapper.h"
#include <iostream>
#include <QApplication>
int main(int argc, char *argv[])
{
int ret;
QApplication a(argc, argv);
MainWindow w;
LibUsbInit();
w.show();
ret = a.exec();
LibUsbDeInit();
return ret;
}

View File

@ -0,0 +1,228 @@
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "libusbwrapper.h"
#include <QMessageBox>
#include <memory>
#include <iostream>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->rescanButton, SIGNAL(clicked()), this, SLOT(rescan_clicked()));
connect(this, SIGNAL(close()), this, SLOT(on_close()));
connect(ui->deviceComboBox, SIGNAL(currentTextChanged(QString)), this, SLOT(device_changed(QString)));
connect(ui->clearKeycodesButton, SIGNAL(clicked()), this, SLOT(clear_keyboard_config()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::rescan_device_list()
{
if (this->m_usb_devices.size()) {
/* Close old devices */
m_usb_devices.clear();
}
auto temp_vector = UsbDevice::find_devices(0xDEAD, 0xBEEF);
this->m_usb_devices = std::vector<SustainPedalKeyboard>(temp_vector.begin(), temp_vector.end());
ui->deviceComboBox->clear();
/* Update combo box with devices */
for (auto &dev : m_usb_devices) {
dev.open();
auto sn = dev.get_serial_number();
ui->deviceComboBox->addItem(QString::fromStdString(sn));
}
}
UsbDevice *MainWindow::get_device_from_sn(const std::string &sn)
{
for (auto &d : m_usb_devices) {
if (d.get_serial_number() == sn)
return &d;
}
return NULL;
}
UsbHidKeyEvent MainWindow::create_key_event_pedal1()
{
UsbHidKeyEvent event;
event.left_control = ui->checkBoxLControl_1->isChecked();
event.left_shift = ui->checkBoxLShift_1->isChecked();
event.left_alt = ui->checkBoxLAlt_1->isChecked();
event.left_super = ui->checkBoxLSuper_1->isChecked();
event.right_control = ui->checkBoxRControl_1->isChecked();
event.right_shift = ui->checkBoxRShift_1->isChecked();
event.right_alt = ui->checkBoxRAlt_1->isChecked();
event.right_super = ui->checkBoxRSuper_1->isChecked();
event.keycodes[0] = (uint8_t)ui->keycode1_1->value();
event.keycodes[1] = (uint8_t)ui->keycode2_1->value();
event.keycodes[2] = (uint8_t)ui->keycode3_1->value();
return event;
}
UsbHidKeyEvent MainWindow::create_key_event_pedal2()
{
UsbHidKeyEvent event;
event.left_control = ui->checkBoxLControl_2->isChecked();
event.left_shift = ui->checkBoxLShift_2->isChecked();
event.left_alt = ui->checkBoxLAlt_2->isChecked();
event.left_super = ui->checkBoxLSuper_2->isChecked();
event.right_control = ui->checkBoxRControl_2->isChecked();
event.right_shift = ui->checkBoxRShift_2->isChecked();
event.right_alt = ui->checkBoxRAlt_2->isChecked();
event.right_super = ui->checkBoxRSuper_2->isChecked();
event.keycodes[0] = (uint8_t)ui->keycode1_2->value();
event.keycodes[1] = (uint8_t)ui->keycode2_2->value();
event.keycodes[2] = (uint8_t)ui->keycode3_2->value();
return event;
}
void MainWindow::rescan_clicked()
{
rescan_device_list();
}
void MainWindow::device_changed(QString sn)
{
auto dev = get_device_from_sn(sn.toStdString());
if (m_currently_selected_dev.get()) {
m_currently_selected_dev->set_active_indicator(false);
}
m_currently_selected_dev.reset();
if (dev == NULL) {
enable_pedal_gui_elements(false);
return;
}
enable_pedal_gui_elements(true);
m_currently_selected_dev = std::make_unique<SustainPedalKeyboard>(*dev);
m_currently_selected_dev->set_active_indicator(true);
update_gui_from_keyboard();
}
void MainWindow::clear_keyboard_config()
{
if (!m_currently_selected_dev.get()) {
QMessageBox::warning(this, "Error", "No device selected!");
return;
}
UsbHidKeyEvent empty_key;
if (m_currently_selected_dev->program_keyboard_keycode(0, empty_key)) {
QMessageBox::warning(this, "Error", "Request to device failed!");
return;
}
if (m_currently_selected_dev->program_keyboard_keycode(1, empty_key)) {
QMessageBox::warning(this, "Error", "Request to device failed!");
return;
}
update_gui_from_keyboard();
QMessageBox::information(this, "Device Reset", "All configuration deleted!");
}
void MainWindow::update_gui_from_keyboard()
{
UsbHidKeyEvent pedal1, pedal2;
if (!m_currently_selected_dev->read_keyboard_config(&pedal1, &pedal2)) {
ui->checkBoxLControl_1->setChecked(pedal1.left_control);
ui->checkBoxLShift_1->setChecked(pedal1.left_shift);
ui->checkBoxLAlt_1->setChecked(pedal1.left_alt);
ui->checkBoxLSuper_1->setChecked(pedal1.left_super);
ui->checkBoxRControl_1->setChecked(pedal1.right_control);
ui->checkBoxRShift_1->setChecked(pedal1.right_shift);
ui->checkBoxRAlt_1->setChecked(pedal1.right_alt);
ui->checkBoxRSuper_1->setChecked(pedal1.right_super);
ui->checkBoxLControl_2->setChecked(pedal2.left_control);
ui->checkBoxLShift_2->setChecked(pedal2.left_shift);
ui->checkBoxLAlt_2->setChecked(pedal2.left_alt);
ui->checkBoxLSuper_2->setChecked(pedal2.left_super);
ui->checkBoxRControl_2->setChecked(pedal2.right_control);
ui->checkBoxRShift_2->setChecked(pedal2.right_shift);
ui->checkBoxRAlt_2->setChecked(pedal2.right_alt);
ui->checkBoxRSuper_2->setChecked(pedal2.right_super);
ui->keycode1_1->setValue((int)pedal1.keycodes[0]);
ui->keycode2_1->setValue((int)pedal1.keycodes[1]);
ui->keycode3_1->setValue((int)pedal1.keycodes[2]);
ui->keycode1_2->setValue((int)pedal2.keycodes[0]);
ui->keycode2_2->setValue((int)pedal2.keycodes[1]);
ui->keycode3_2->setValue((int)pedal2.keycodes[2]);
}
}
void MainWindow::closeEvent(QCloseEvent *event)
{
if (m_currently_selected_dev)
m_currently_selected_dev->set_active_indicator(false);
m_usb_devices.clear();
m_currently_selected_dev.reset();
m_currently_selected_dev = nullptr;
}
void MainWindow::showEvent(QShowEvent *event)
{
QMainWindow::showEvent(event);
enable_pedal_gui_elements(false);
rescan_device_list();
}
void MainWindow::on_buttonProgPedal1_clicked()
{
if (!m_currently_selected_dev.get())
return;
auto ev = create_key_event_pedal1();
m_currently_selected_dev->program_keyboard_keycode(0, ev);
}
void MainWindow::on_buttonProgPedal2_clicked()
{
if (!m_currently_selected_dev.get())
return;
auto ev = create_key_event_pedal2();
m_currently_selected_dev->program_keyboard_keycode(1, ev);
}
void MainWindow::enable_pedal_gui_elements(bool enable)
{
int count1 = ui->verticalLayoutPedal1->count();
int count2 = ui->verticalLayoutPedal2->count();
for (int i = 0; i < count1; i++) {
ui->verticalLayoutPedal1->itemAt(i)->widget()->setEnabled(enable);
}
for (int i = 0; i < count2; i++) {
ui->verticalLayoutPedal2->itemAt(i)->widget()->setEnabled(enable);
}
ui->clearKeycodesButton->setEnabled(enable);
}

View File

@ -0,0 +1,47 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "sustainpedalkeyboard.h"
#include <vector>
#include <optional>
#include <functional>
#include <memory>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
void rescan_device_list(void);
UsbDevice *get_device_from_sn(const std::string &sn);
std::vector<SustainPedalKeyboard> m_usb_devices;
std::unique_ptr<SustainPedalKeyboard> m_currently_selected_dev;
UsbHidKeyEvent create_key_event_pedal1();
UsbHidKeyEvent create_key_event_pedal2();
private slots:
void rescan_clicked();
void device_changed(QString sn);
void clear_keyboard_config();
void update_gui_from_keyboard();
void on_buttonProgPedal1_clicked();
void on_buttonProgPedal2_clicked();
void enable_pedal_gui_elements(bool enable);
protected:
void closeEvent(QCloseEvent *event);
void showEvent(QShowEvent *event);
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,251 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Shimatta Sustain Pedal Keyboard Configuration</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QWidget" name="verticalLayoutWidget_3">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>501</width>
<height>492</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QComboBox" name="deviceComboBox"/>
</item>
<item>
<widget class="QPushButton" name="rescanButton">
<property name="text">
<string>Rescan Device List</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSpinBox" name="spinBoxVid"/>
</item>
<item>
<widget class="QSpinBox" name="spinBoxPid"/>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Program VID:PID</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="clearKeycodesButton">
<property name="text">
<string>Clear Keycodes</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="pedalUiElements">
<item>
<layout class="QVBoxLayout" name="verticalLayoutPedal1">
<item>
<widget class="QCheckBox" name="checkBoxLControl_1">
<property name="text">
<string>Left Control</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxLShift_1">
<property name="text">
<string>Left Shift</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxLAlt_1">
<property name="text">
<string>Left Alt</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxLSuper_1">
<property name="text">
<string>Left Super</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxRControl_1">
<property name="text">
<string>Right Control</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxRShift_1">
<property name="text">
<string>Right Shift</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxRAlt_1">
<property name="text">
<string>Right Alt</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxRSuper_1">
<property name="text">
<string>Right Super</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="keycode1_1">
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="keycode2_1">
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="keycode3_1">
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonProgPedal1">
<property name="text">
<string>Program Pedal 1</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayoutPedal2">
<item>
<widget class="QCheckBox" name="checkBoxLControl_2">
<property name="text">
<string>Left Control</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxLShift_2">
<property name="text">
<string>Left Shift</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxLAlt_2">
<property name="text">
<string>Left Alt</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxLSuper_2">
<property name="text">
<string>Left Super</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxRControl_2">
<property name="text">
<string>Right Control</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxRShift_2">
<property name="text">
<string>Right Shift</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxRAlt_2">
<property name="text">
<string>Right Alt</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxRSuper_2">
<property name="text">
<string>Right Super</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="keycode1_2">
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="keycode2_2">
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="keycode3_2">
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonProgPedal2">
<property name="text">
<string>Program Pedal 2</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,155 @@
#include "sustainpedalkeyboard.h"
#include <iostream>
SustainPedalKeyboard::SustainPedalKeyboard(libusb_device *device) : UsbDevice(device)
{
m_control_timeout = 500;
}
SustainPedalKeyboard::SustainPedalKeyboard(const UsbDevice &device) : UsbDevice(device)
{
m_control_timeout = 500;
}
SustainPedalKeyboard::~SustainPedalKeyboard()
{
}
int SustainPedalKeyboard::get_control_timeout()
{
return m_control_timeout;
}
void SustainPedalKeyboard::set_control_timeout(int timeout)
{
m_control_timeout = timeout;
}
int SustainPedalKeyboard::set_led(uint8_t led, bool state)
{
int res = this->control_transfer((1<<6), 0x1, state ? 1 : 0, led, NULL, 0, m_control_timeout);
return res;
}
void SustainPedalKeyboard::set_active_indicator(bool state)
{
(void)set_led(3, state);
}
int SustainPedalKeyboard::program_keyboard_keycode(uint8_t pedal_idx, UsbHidKeyEvent &key)
{
uint32_t word;
uint8_t data[4];
if (pedal_idx > 1)
return -1001;
word = key.to_eeprom_word();
for (int i = 0; i < 4; i++) {
data[i] = word & 0xFF;
word >>= 8;
}
int res = write_eeprom(pedal_idx * 4, data, 4);
if (res < 0)
return res;
else
return 0;
}
int SustainPedalKeyboard::read_keyboard_config(UsbHidKeyEvent *pedal1, UsbHidKeyEvent *pedal2)
{
unsigned char eeprom_data[8];
if (!pedal1 || !pedal2)
return -1000;
int res = read_eeprom(0, eeprom_data, sizeof(eeprom_data));
if (res != 8) {
return -1;
}
pedal1->from_eeprom_data(&eeprom_data[0]);
pedal2->from_eeprom_data(&eeprom_data[4]);
return 0;
}
int SustainPedalKeyboard::write_eeprom(uint16_t offset_addr, unsigned char *data, uint16_t len)
{
return this->control_transfer((1<<6), 0x2, 0, offset_addr, data, len, m_control_timeout);
}
int SustainPedalKeyboard::read_eeprom(uint16_t offset_addr, unsigned char *data, uint16_t len)
{
int ret;
ret = this->control_transfer(0x80 | (1<<6), 0x2, 0x0, offset_addr, data, len, m_control_timeout);
return ret;
}
UsbHidKeyEvent::UsbHidKeyEvent()
{
for (int i = 0; i < 3; i++)
keycodes[i] = 0;
left_control = false;
left_alt = false;
left_shift = false;
left_super = false;
right_control = false;
right_super = false;
right_alt = false;
right_shift = false;
}
uint32_t UsbHidKeyEvent::to_eeprom_word()
{
uint8_t modifiers = 0;
uint32_t ret;
if (left_control)
modifiers |= 1;
if (left_shift)
modifiers |= 2;
if (left_alt)
modifiers |= 4;
if (left_super)
modifiers |= 8;
if (right_control)
modifiers |= 16;
if (right_shift)
modifiers |= 32;
if (right_alt)
modifiers |= 64;
if (right_super)
modifiers |= 128;
ret = (uint32_t)modifiers;
ret |= (((uint32_t)keycodes[0]) << 8);
ret |= (((uint32_t)keycodes[1]) << 16);
ret |= (((uint32_t)keycodes[2]) << 24);
return ret;
}
void UsbHidKeyEvent::from_eeprom_data(uint8_t data[4])
{
left_control = !!(data[0] & 1);
left_shift = !!(data[0] & 2);
left_alt = !!(data[0] & 4);
left_super = !!(data[0] & 8);
right_control = !!(data[0] & 16);
right_shift = !!(data[0] & 32);
right_alt = !!(data[0] & 64);
right_super = !!(data[0] & 128);
for (int i = 0; i < 3; i++) {
keycodes[i] = data[i + 1];
}
}

View File

@ -0,0 +1,50 @@
#ifndef SUSTAINPEDALKEYBOARD_H
#define SUSTAINPEDALKEYBOARD_H
#include "libusbwrapper.h"
class UsbHidKeyEvent {
public:
UsbHidKeyEvent();
bool left_control;
bool left_shift;
bool left_alt;
bool left_super;
bool right_control;
bool right_shift;
bool right_alt;
bool right_super;
uint8_t keycodes[3];
uint32_t to_eeprom_word();
void from_eeprom_data(uint8_t data[4]);
};
class SustainPedalKeyboard : public UsbDevice
{
public:
SustainPedalKeyboard(libusb_device *device);
SustainPedalKeyboard(const UsbDevice &device);
~SustainPedalKeyboard();
int get_control_timeout();
void set_control_timeout(int timeout);
int set_led(uint8_t led, bool state);
void set_active_indicator(bool state);
int program_keyboard_keycode(uint8_t pedal_idx, UsbHidKeyEvent &key);
int read_keyboard_config(UsbHidKeyEvent *pedal1, UsbHidKeyEvent *pedal2);
private:
int write_eeprom(uint16_t offset_addr, unsigned char *data, uint16_t len);
int read_eeprom(uint16_t offset_addr, unsigned char *data, uint16_t len);
int m_control_timeout;
};
#endif // SUSTAINPEDALKEYBOARD_H